parent
1e05f977f6
commit
5e4a81c303
@ -1,34 +1,127 @@ |
||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; |
||||
import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common'; |
||||
import { AuthUserService } from './auth-user.service'; |
||||
import { CreateAuthUserDto } from './dto/create-auth-user.dto'; |
||||
import { UpdateAuthUserDto } from './dto/update-auth-user.dto'; |
||||
import { ApiOperation, ApiProduces, ApiTags } from '@nestjs/swagger'; |
||||
import { PacInfo } from '@common/decorator/pac-info/pac-info.decorator'; |
||||
import { PacInfoType } from '@utils/myType'; |
||||
import { GetPacAuthUserAllDto } from '@app/auth-user/dto/get-auth-user.dto'; |
||||
import { PasswordDto } from '@app/auth-user/dto/password.dto'; |
||||
import { UpdateLinkDto } from '@app/auth-user/dto/updateLink.dto'; |
||||
import {UsernameSignInDto} from "@app/auth-user/dto/signin.dto"; |
||||
|
||||
@Controller('auth-user') |
||||
@ApiTags('账户服务') |
||||
@Controller('authUser') |
||||
export class AuthUserController { |
||||
constructor(private readonly authUserService: AuthUserService) {} |
||||
|
||||
@ApiOperation({ |
||||
summary: '添加账户', |
||||
description: '账户', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Post() |
||||
create(@Body() createAuthUserDto: CreateAuthUserDto) { |
||||
return this.authUserService.create(createAuthUserDto); |
||||
create(@Body() createAuthUserDto: CreateAuthUserDto, @PacInfo() pacInfo: PacInfoType) { |
||||
return this.authUserService.create(createAuthUserDto, pacInfo); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '获取账户列表', |
||||
description: '查询账户分页或者列表', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Get() |
||||
findAll() { |
||||
return this.authUserService.findAll(); |
||||
findAll(@Query() getPacAuthUserAllDto: GetPacAuthUserAllDto) { |
||||
return this.authUserService.findAll(getPacAuthUserAllDto); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '获取账户详细信息', |
||||
description: '查询账户详细信息,目录菜单列表,数据权限范围', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Get(':id') |
||||
findOne(@Param('id') id: string) { |
||||
return this.authUserService.findOne(+id); |
||||
return this.authUserService.findOne(id); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '更新账户信息', |
||||
description: '更新账户信息', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Patch(':id') |
||||
update(@Param('id') id: string, @Body() updateAuthUserDto: UpdateAuthUserDto) { |
||||
return this.authUserService.update(+id, updateAuthUserDto); |
||||
update(@Param('id') id: string, @Body() updateAuthUserDto: UpdateAuthUserDto, @PacInfo() pacInfo: PacInfoType) { |
||||
return this.authUserService.update(id, updateAuthUserDto, pacInfo); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '删除目标账户', |
||||
description: '删除目标账户信息', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Delete(':id') |
||||
remove(@Param('id') id: string) { |
||||
return this.authUserService.remove(+id); |
||||
remove(@Param('id') id: string, @PacInfo() pacInfo: PacInfoType) { |
||||
return this.authUserService.remove(id, pacInfo); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '重置密码', |
||||
description: '给指定用户将密码恢复为系统默认账户密码', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Post('/password/:id') |
||||
resetTargetUserPassword(@Param('id') id: string) { |
||||
return this.authUserService.resetTargetUserPassword(id); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '修改密码', |
||||
description: '修改自己密码', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Patch('/password') |
||||
updatePassword(@Param('id') id: string, @Body() passwordDto: PasswordDto) { |
||||
return this.authUserService.updatePassword(id, passwordDto); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '更新账户角色', |
||||
description: '更新账户角色', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Patch('/role/:id') |
||||
updateLinkRole(@Param('id') id: string, @Body() updateLinkDto: UpdateLinkDto, @PacInfo() pacInfo: PacInfoType) { |
||||
return this.authUserService.updateLinkRole(id, updateLinkDto, pacInfo); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '更新账户部门', |
||||
description: '更新账户部门', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Patch('/dept/:id') |
||||
updateLinkDept(@Param('id') id: string, @Body() updateLinkDto: UpdateLinkDto, @PacInfo() pacInfo: PacInfoType) { |
||||
return this.authUserService.updateLinkDept(id, updateLinkDto, pacInfo); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '更新账户岗位', |
||||
description: '更新账户岗位', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Patch('/post/:id') |
||||
updateLinkPost(@Param('id') id: string, @Body() updateLinkDto: UpdateLinkDto, @PacInfo() pacInfo: PacInfoType) { |
||||
return this.authUserService.updateLinkPost(id, updateLinkDto, pacInfo); |
||||
} |
||||
|
||||
@ApiOperation({ |
||||
summary: '登陆系统', |
||||
description: '登陆系统', |
||||
}) |
||||
@ApiProduces('application/json') |
||||
@Post('/signin') |
||||
signin(@Body() usernameSignInDto: UsernameSignInDto) { |
||||
return this.authUserService.signin(usernameSignInDto); |
||||
} |
||||
} |
||||
|
@ -1,9 +1,10 @@ |
||||
import { Module } from '@nestjs/common'; |
||||
import { AuthUserService } from './auth-user.service'; |
||||
import { AuthUserController } from './auth-user.controller'; |
||||
import { JwtService } from '@common/service/jwt/jwt.service'; |
||||
|
||||
@Module({ |
||||
controllers: [AuthUserController], |
||||
providers: [AuthUserService], |
||||
providers: [AuthUserService, JwtService], |
||||
}) |
||||
export class AuthUserModule {} |
||||
|
@ -1,26 +1,696 @@ |
||||
import { Injectable } from '@nestjs/common'; |
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; |
||||
import { CreateAuthUserDto } from './dto/create-auth-user.dto'; |
||||
import { UpdateAuthUserDto } from './dto/update-auth-user.dto'; |
||||
import { PacInfoType } from '@utils/myType'; |
||||
import { LoggerService } from '@service/logger/logger.service'; |
||||
import { MysqlService } from '@common/service/mysql/mysql.service'; |
||||
import { RedisService } from '@common/service/redis/redis.service'; |
||||
import { Snowflake } from '@service/snowflake/snowflake.service'; |
||||
import { ConfigService } from '@nestjs/config'; |
||||
import { |
||||
pacAuthDept, |
||||
pacAuthLinkRoleMenu, |
||||
pacAuthLinkUserDept, |
||||
pacAuthLinkUserPost, |
||||
pacAuthLinkUserRole, |
||||
pacAuthPost, |
||||
pacAuthRole, |
||||
pacAuthUser, |
||||
pacCoreDict, |
||||
} from '@entities/schema'; |
||||
import { and, asc, desc, eq, gt, isNull, like, or, sql } from 'drizzle-orm'; |
||||
import cryptoPassword from '@utils/cryptoPassword'; |
||||
import { GetPacAuthUserAllDto } from '@app/auth-user/dto/get-auth-user.dto'; |
||||
import { isExistKey, isTrueEnum } from '@utils/boolean.enum'; |
||||
import { likeQuery } from '@utils/likeQuery'; |
||||
import { alias } from 'drizzle-orm/mysql-core'; |
||||
import { from } from 'rxjs'; |
||||
import { UpdateCoreDictDto } from '@app/core-dict/dto/update-core-dict.dto'; |
||||
import { PasswordDto } from '@app/auth-user/dto/password.dto'; |
||||
import { UpdateLinkDto } from '@app/auth-user/dto/updateLink.dto'; |
||||
import { UsernameSignInDto } from '@app/auth-user/dto/signin.dto'; |
||||
import { JwtService } from '@common/service/jwt/jwt.service'; |
||||
import MD5 from '@utils/MD5'; |
||||
|
||||
@Injectable() |
||||
export class AuthUserService { |
||||
create(createAuthUserDto: CreateAuthUserDto) { |
||||
// 分页数据
|
||||
private readonly userPageType = { |
||||
userId: pacAuthUser.userId, |
||||
username: pacAuthUser.username, |
||||
nickname: pacAuthUser.nickname, |
||||
userType: pacAuthUser.userType, |
||||
userTypeName: pacCoreDict.dictName, |
||||
userTypeKey: pacCoreDict.dictKey, |
||||
userEmail: pacAuthUser.userEmail, |
||||
pid: pacAuthUser.pid, |
||||
wxAppid: pacAuthUser.wxAppid, |
||||
avatar: pacAuthUser.avatar, |
||||
userPhone: pacAuthUser.userPhone, |
||||
userDesc: pacAuthUser.userDesc, |
||||
status: pacAuthUser.status, |
||||
haveChildren: pacAuthUser.haveChildren, |
||||
createby: pacAuthUser.createby, |
||||
createtime: pacAuthUser.createtime, |
||||
updateby: pacAuthUser.updateby, |
||||
updatetime: pacAuthUser.updatetime, |
||||
}; |
||||
|
||||
// 列表数据
|
||||
private readonly userListType = { |
||||
userId: pacAuthUser.userId, |
||||
username: pacAuthUser.username, |
||||
nickname: pacAuthUser.nickname, |
||||
userType: pacAuthUser.userType, |
||||
userTypeName: pacCoreDict.dictName, |
||||
userTypeKey: pacCoreDict.dictKey, |
||||
}; |
||||
constructor( |
||||
private readonly logger: LoggerService, |
||||
private readonly mysqlService: MysqlService, |
||||
private readonly redisService: RedisService, |
||||
private readonly snowflake: Snowflake, |
||||
private readonly config: ConfigService, |
||||
private readonly jwt: JwtService, |
||||
) {} |
||||
|
||||
/** Service |
||||
* NAME: create |
||||
* DESC: 创建账户 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async create(createAuthUserDto: CreateAuthUserDto, pacInfo: PacInfoType) { |
||||
// ! 加目标锁,同级,而不是全局
|
||||
const lock = await this.redisService.distributedLock('USER' + createAuthUserDto.username, createAuthUserDto.username); |
||||
|
||||
// ? 存在正在进行写入的账户
|
||||
if (!lock) throw new HttpException('服务繁忙,账户名称重复!', HttpStatus.CONFLICT); |
||||
|
||||
try { |
||||
// ! 用户名查重
|
||||
const result = await this.checkRepeatForUsername(createAuthUserDto.username); |
||||
|
||||
// ? 是否存在重复的账户
|
||||
if (result.length > 0) throw new HttpException('用户名重复!', HttpStatus.CONFLICT); |
||||
|
||||
// ! 添加账户数据
|
||||
const newPacCoreDict = await this.addUser(createAuthUserDto, pacInfo); |
||||
|
||||
// ! 解锁
|
||||
lock(); |
||||
|
||||
const insertList = []; |
||||
|
||||
// ! 关联角色
|
||||
if (createAuthUserDto.roleList && createAuthUserDto.roleList.length > 0) { |
||||
insertList.push(this.updateUserRole(newPacCoreDict.userId as any, createAuthUserDto.roleList, pacInfo)); |
||||
} |
||||
|
||||
// ! 关联部门
|
||||
if (createAuthUserDto.deptList && createAuthUserDto.deptList.length > 0) { |
||||
insertList.push(this.updateUserDept(newPacCoreDict.userId as any, createAuthUserDto.deptList, pacInfo)); |
||||
} |
||||
|
||||
// ! 关联岗位
|
||||
if (createAuthUserDto.postList && createAuthUserDto.postList.length > 0) { |
||||
insertList.push(this.updateUserPost(newPacCoreDict.userId as any, createAuthUserDto.postList, pacInfo)); |
||||
} |
||||
|
||||
// ! 执行关联
|
||||
await Promise.all(insertList).catch((e) => { |
||||
this.logger.error('新增用户时,关联角色、部门、岗位出现错误'); |
||||
this.logger.error(e); |
||||
}); |
||||
|
||||
// !更新父节点的子节点数量
|
||||
await this.haveChildrenSelfIncreasing(createAuthUserDto.pid); |
||||
|
||||
// ! 返回结果
|
||||
return newPacCoreDict; |
||||
} catch (e) { |
||||
// ! 解锁
|
||||
lock(); |
||||
|
||||
// ! 抛出错误
|
||||
throw e; |
||||
} |
||||
|
||||
return 'This action adds a new authUser'; |
||||
} |
||||
|
||||
findAll() { |
||||
return `This action returns all authUser`; |
||||
/** Service |
||||
* NAME: findAll |
||||
* DESC: 查找用户分页/列表 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async findAll(getPacAuthUserAllDto: GetPacAuthUserAllDto) { |
||||
if (isTrueEnum(getPacAuthUserAllDto['isList'])) { |
||||
return await this.getList(getPacAuthUserAllDto); |
||||
} else { |
||||
return await this.getPage(getPacAuthUserAllDto); |
||||
} |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: findOne |
||||
* DESC: 查用户详细信息 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async findOne(id: string) { |
||||
return await this.getMore(id); |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: update |
||||
* DESC: 修改账户信息 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public update(id: string, updateAuthUserDto: UpdateAuthUserDto, pacInfo: PacInfoType) { |
||||
return this.updateUser(id, updateAuthUserDto, pacInfo); |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: remove |
||||
* DESC: 移除账户 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public remove(id: string, pacInfo: PacInfoType) { |
||||
return this.deleteUser(id, pacInfo.userId as any); |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: resetTargetUserPassword |
||||
* DESC: 充值目标账户密码 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async resetTargetUserPassword(id: string) { |
||||
return this.resetPassword(id, null); |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: updatePassword |
||||
* DESC: 修改自己账户密码 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async updatePassword(id: string, passwordDto: PasswordDto) { |
||||
const user = await this.mysqlService.db |
||||
.select({ |
||||
password: pacAuthUser.password, |
||||
}) |
||||
.from(pacAuthUser) |
||||
.where(eq(pacAuthUser.userId, id)); |
||||
if (user.length == 0) throw new HttpException('未找到目标用户信息,无法修改密码!', HttpStatus.BAD_REQUEST); |
||||
const oldPassword = cryptoPassword(passwordDto.oldPassword, this.config.get<number>('system.passwordSalt')); |
||||
if (oldPassword != user[0].password) throw new HttpException('原密码错误!', HttpStatus.BAD_REQUEST); |
||||
return this.resetPassword(id, passwordDto.newPassword); |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: updatePassword |
||||
* DESC: 修改目标账户角色关联 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async updateLinkRole(id: string, updateLinkDto: UpdateLinkDto, pacInfo: PacInfoType) { |
||||
await this.checkUserExist(id); |
||||
if (updateLinkDto) { |
||||
return this.updateUserRole(id, updateLinkDto.list, pacInfo); |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: updateLinkDept |
||||
* DESC: 修改目标账户部门关联 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async updateLinkDept(id: string, updateLinkDto: UpdateLinkDto, pacInfo: PacInfoType) { |
||||
await this.checkUserExist(id); |
||||
if (updateLinkDto) { |
||||
return this.updateUserDept(id, updateLinkDto.list, pacInfo); |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: updateLinkPost |
||||
* DESC: 修改目标账户岗位关联 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async updateLinkPost(id: string, updateLinkDto: UpdateLinkDto, pacInfo: PacInfoType) { |
||||
await this.checkUserExist(id); |
||||
if (updateLinkDto) { |
||||
return this.updateUserPost(id, updateLinkDto.list, pacInfo); |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
/** Service |
||||
* NAME: updateLinkPost |
||||
* DESC: 修改目标账户岗位关联 |
||||
* DATE: 2024-06-29 13:13:55 - |
||||
* */ |
||||
public async signin(usernameSignInDto: UsernameSignInDto) { |
||||
// 登陆检测
|
||||
return await this.signinDetection(usernameSignInDto); |
||||
} |
||||
|
||||
// DB 同级查重
|
||||
private checkRepeatForUsername(username: string) { |
||||
return this.mysqlService.db |
||||
.select({ |
||||
id: pacAuthUser.username, |
||||
}) |
||||
.from(pacAuthUser) |
||||
.where(and(isNull(pacAuthUser.deleteby), eq(pacAuthUser.username, username))); |
||||
} |
||||
|
||||
// DB 更新父级子元素数量
|
||||
private async haveChildrenSelfIncreasing(id: string, isAdd = true) { |
||||
return this.mysqlService.db |
||||
.update(pacAuthUser) |
||||
.set({ |
||||
haveChildren: isAdd ? sql`${pacAuthUser.haveChildren} + 1` : sql`${pacAuthUser.haveChildren} - 1`, |
||||
}) |
||||
.where(eq(pacAuthUser.userId as any, id)); |
||||
} |
||||
|
||||
// DB 添加账户
|
||||
private async addUser(createAuthUserDto: CreateAuthUserDto, pacInfo: PacInfoType) { |
||||
// ! 生成雪花id,用于账户id
|
||||
const id = await this.snowflake.generate(); |
||||
|
||||
let password = ''; |
||||
|
||||
// ! 从Redis获取默认密码
|
||||
const defaultPasswordForRedis = await this.redisService.get('ENV_DEFAULT_PASSWORD'); |
||||
|
||||
// ? 判断redis中是否存在默认密码环境变量
|
||||
if (!defaultPasswordForRedis) { |
||||
password = this.config.get<string>('system.defaultPassword'); |
||||
} else { |
||||
password = defaultPasswordForRedis; |
||||
} |
||||
|
||||
// ! 加密密码
|
||||
const pass = cryptoPassword(password, this.config.get<number>('system.passwordSalt')); |
||||
|
||||
// ! 定义写入的账户数据
|
||||
const newUserData: typeof pacAuthUser.$inferInsert = { |
||||
userId: id as any, |
||||
username: createAuthUserDto.username, |
||||
password: pass, |
||||
nickname: createAuthUserDto.nickname, |
||||
userType: createAuthUserDto.userType, |
||||
userEmail: createAuthUserDto.userEmail, |
||||
pid: createAuthUserDto.pid, |
||||
avatar: createAuthUserDto.avatar, |
||||
userPhone: createAuthUserDto.userPhone, |
||||
userDesc: createAuthUserDto.userDesc, |
||||
createby: pacInfo.userId as any, |
||||
createtime: sql`now()` as any, |
||||
}; |
||||
return { |
||||
insert: await this.mysqlService.db.insert(pacAuthUser).values(newUserData), |
||||
userId: id.toString(), |
||||
}; |
||||
} |
||||
|
||||
// COMMON 去重数组
|
||||
private deduplicateArray(arr: string[]) { |
||||
return Array.from(new Set(arr)); |
||||
} |
||||
|
||||
findOne(id: number) { |
||||
return `This action returns a #${id} authUser`; |
||||
// COMMON 向目标表插入列
|
||||
private async insertKeyValueForUserLink(table, list, key, userId, pacInfo: PacInfoType) { |
||||
// ! 清空曾经的关联
|
||||
await this.mysqlService.db.delete(table).where(eq(table.userId as any, userId)); |
||||
|
||||
// ! 去重列表
|
||||
const arr = this.deduplicateArray(list); |
||||
|
||||
// ! 增加新的关联
|
||||
return await this.mysqlService.db.insert(table).values( |
||||
arr.map((i) => ({ |
||||
userId: userId, |
||||
[key]: i, |
||||
createby: pacInfo.userId as any, |
||||
createtime: sql`now()` as any, |
||||
})), |
||||
); |
||||
} |
||||
|
||||
// DB 修改用户角色
|
||||
private async updateUserRole(userId: string, roleIdList: string[], pacInfo: PacInfoType) { |
||||
return await this.insertKeyValueForUserLink(pacAuthLinkUserRole, roleIdList, 'roleId', userId, pacInfo); |
||||
} |
||||
|
||||
update(id: number, updateAuthUserDto: UpdateAuthUserDto) { |
||||
return `This action updates a #${id} authUser`; |
||||
// DB 修改账户部门
|
||||
private async updateUserDept(userId: string, deptIdList: string[], pacInfo: PacInfoType) { |
||||
return await this.insertKeyValueForUserLink(pacAuthLinkUserDept, deptIdList, 'deptId', userId, pacInfo); |
||||
} |
||||
|
||||
remove(id: number) { |
||||
return `This action removes a #${id} authUser`; |
||||
// DB修改账户岗位
|
||||
private async updateUserPost(userId: string, postIdList: string[], pacInfo: PacInfoType) { |
||||
return await this.insertKeyValueForUserLink(pacAuthLinkUserPost, postIdList, 'postId', userId, pacInfo); |
||||
} |
||||
|
||||
// 查询构建器
|
||||
private queryBuilder(getPacAuthUserAllDto: GetPacAuthUserAllDto, selectData) { |
||||
// ! 定义基础查询函数
|
||||
// 启用动态查询模式 $dynamic
|
||||
const query = this.mysqlService.db |
||||
.select(selectData) |
||||
.from(pacAuthUser) |
||||
.orderBy(isTrueEnum(getPacAuthUserAllDto.isAsc) ? asc(pacAuthUser.userId) : desc(pacAuthUser.userId)) |
||||
.leftJoin(pacCoreDict, eq(pacAuthUser.userType, pacCoreDict.dictId)) |
||||
|
||||
// 角色
|
||||
.leftJoin(pacAuthLinkUserRole, eq(pacAuthUser.userId, pacAuthLinkUserRole.userId)) |
||||
|
||||
// 部门
|
||||
.leftJoin(pacAuthLinkUserDept, eq(pacAuthUser.userId, pacAuthLinkUserDept.userId)) |
||||
|
||||
// 岗位
|
||||
.leftJoin(pacAuthLinkUserPost, eq(pacAuthUser.userId, pacAuthLinkUserPost.userId)) |
||||
.$dynamic(); |
||||
|
||||
// 查询条件集合
|
||||
const wl = []; |
||||
|
||||
// ? 未删除
|
||||
wl.push(isNull(pacAuthUser.deleteby)); |
||||
|
||||
// ? 模糊查询
|
||||
wl.push( |
||||
or( |
||||
like(pacAuthUser.username, likeQuery(getPacAuthUserAllDto.userInfo)), |
||||
like(pacAuthUser.nickname, likeQuery(getPacAuthUserAllDto.userInfo)), |
||||
like(pacAuthUser.userEmail, likeQuery(getPacAuthUserAllDto.userInfo)), |
||||
like(pacAuthUser.userPhone, likeQuery(getPacAuthUserAllDto.userInfo)), |
||||
like(pacAuthUser.userDesc, likeQuery(getPacAuthUserAllDto.userInfo)), |
||||
).if(isExistKey(getPacAuthUserAllDto, 'userInfo')), |
||||
); |
||||
|
||||
// ? 按照层级查
|
||||
wl.push(eq(pacAuthUser.pid, getPacAuthUserAllDto.hierarchy).if(isExistKey(getPacAuthUserAllDto, 'hierarchy'))); |
||||
|
||||
// ? 是否查角色类型
|
||||
wl.push(eq(pacAuthUser.userType, getPacAuthUserAllDto.userType).if(isExistKey(getPacAuthUserAllDto, 'userType'))); |
||||
|
||||
// ? 是否查字典状态
|
||||
wl.push(eq(pacAuthUser.status, getPacAuthUserAllDto.status as any).if(isExistKey(getPacAuthUserAllDto, 'status'))); |
||||
|
||||
// ? 是否存在子账户
|
||||
wl.push(gt(pacAuthUser.haveChildren, 0).if(isExistKey(getPacAuthUserAllDto, 'haveChildren') && isTrueEnum(getPacAuthUserAllDto.haveChildren))); |
||||
|
||||
// ? 角色
|
||||
wl.push( |
||||
eq(pacAuthLinkUserRole.roleId, getPacAuthUserAllDto.roleId).if( |
||||
isExistKey(getPacAuthUserAllDto, 'roleId') && !isTrueEnum(getPacAuthUserAllDto.noRole), |
||||
), |
||||
); |
||||
|
||||
// ? 部门
|
||||
wl.push(eq(pacAuthLinkUserDept.deptId, getPacAuthUserAllDto.deptId).if(isExistKey(getPacAuthUserAllDto, 'deptId'))); |
||||
|
||||
// ? 岗位
|
||||
wl.push(eq(pacAuthLinkUserPost.postId, getPacAuthUserAllDto.postId).if(isExistKey(getPacAuthUserAllDto, 'postId'))); |
||||
|
||||
// ? 没有角色
|
||||
wl.push(isNull(pacAuthLinkUserRole.roleId).if(!isExistKey(getPacAuthUserAllDto, 'roleId') && isTrueEnum(getPacAuthUserAllDto.noRole))); |
||||
|
||||
// ? 没有部门
|
||||
wl.push(isNull(pacAuthLinkUserDept.deptId).if(!isExistKey(getPacAuthUserAllDto, 'deptId') && isTrueEnum(getPacAuthUserAllDto.noDept))); |
||||
|
||||
// ? 没有岗位
|
||||
wl.push(isNull(pacAuthLinkUserPost.postId).if(!isExistKey(getPacAuthUserAllDto, 'postId') && isTrueEnum(getPacAuthUserAllDto.noPost))); |
||||
|
||||
query.where(and(...wl)); |
||||
return query; |
||||
} |
||||
|
||||
// DB 查分页
|
||||
private async getPage(getPacAuthUserAllDto: GetPacAuthUserAllDto) { |
||||
const offset = (getPacAuthUserAllDto.pageNumber - 1) * getPacAuthUserAllDto.pageSize; |
||||
|
||||
// ! 使用基础查询构建查询总记录数
|
||||
const totalCountQuery = this.queryBuilder(getPacAuthUserAllDto, { |
||||
totalCount: sql`COUNT(DISTINCT ${pacAuthUser.userId})`, |
||||
}); |
||||
|
||||
// ! 使用基础查询构建分页查询
|
||||
// 重命名表
|
||||
const userTable1 = alias(pacAuthUser, 'userTable1'); |
||||
const userTable2 = alias(pacAuthUser, 'userTable2'); |
||||
const selectObject = { |
||||
...this.userPageType, |
||||
updateName: userTable1.nickname, |
||||
createName: userTable2.nickname, |
||||
}; |
||||
const paginatedQuery = this.queryBuilder(getPacAuthUserAllDto, { |
||||
...selectObject, |
||||
roleList: sql`GROUP_CONCAT(DISTINCT ${pacAuthRole.roleName} ORDER BY ${pacAuthRole.orderNum} DESC SEPARATOR ',')`, |
||||
deptList: sql`GROUP_CONCAT(DISTINCT ${pacAuthDept.deptName} ORDER BY ${pacAuthRole.orderNum} DESC SEPARATOR ',')`, |
||||
postList: sql`GROUP_CONCAT(DISTINCT ${pacAuthPost.postName} ORDER BY ${pacAuthRole.orderNum} DESC SEPARATOR ',')`, |
||||
}) |
||||
.leftJoin(userTable2, eq(pacAuthUser.createby, userTable2.userId)) |
||||
.leftJoin(userTable1, eq(pacAuthUser.updateby, userTable1.userId)) |
||||
.leftJoin(pacAuthRole, eq(pacAuthLinkUserRole.roleId, pacAuthRole.roleId)) |
||||
.leftJoin(pacAuthDept, eq(pacAuthLinkUserDept.deptId, pacAuthDept.deptId)) |
||||
.leftJoin(pacAuthPost, eq(pacAuthLinkUserPost.postId, pacAuthPost.postId)) |
||||
.limit(getPacAuthUserAllDto.pageSize) |
||||
.groupBy(pacAuthUser.userId) |
||||
.offset(offset); |
||||
return { |
||||
total: (await totalCountQuery)[0].totalCount, |
||||
rowData: await paginatedQuery, |
||||
searchData: getPacAuthUserAllDto, |
||||
}; |
||||
} |
||||
|
||||
// DB 查列表
|
||||
private async getList(getPacAuthUserAllDto: GetPacAuthUserAllDto) { |
||||
return this.queryBuilder(getPacAuthUserAllDto, this.userListType); |
||||
} |
||||
|
||||
// DB 查详情
|
||||
private async getMore(id: string) { |
||||
const userTable1 = alias(pacAuthUser, 'userTable1'); |
||||
const userTable2 = alias(pacAuthUser, 'userTable2'); |
||||
const user = await this.mysqlService.db |
||||
.select({ |
||||
...this.userPageType, |
||||
updateName: userTable1.nickname, |
||||
createName: userTable2.nickname, |
||||
}) |
||||
.from(pacAuthUser) |
||||
.leftJoin(pacCoreDict, eq(pacAuthUser.userType, pacCoreDict.dictId)) |
||||
.leftJoin(userTable2, eq(pacAuthUser.createby, userTable2.userId)) |
||||
.leftJoin(userTable1, eq(pacAuthUser.updateby, userTable1.userId)) |
||||
.where(and(eq(pacAuthUser.userId, id), isNull(pacAuthUser.deleteby))); |
||||
|
||||
if (user.length == 0) throw new HttpException('未找到目标用户信息!', HttpStatus.BAD_REQUEST); |
||||
const roleList = await this.mysqlService.db |
||||
.select({ |
||||
roleId: pacAuthRole.roleId, |
||||
roleName: pacAuthRole.roleName, |
||||
roleKey: pacAuthRole.roleKey, |
||||
}) |
||||
.from(pacAuthRole) |
||||
.leftJoin(pacAuthLinkUserRole, eq(pacAuthLinkUserRole.roleId, pacAuthRole.roleId)) |
||||
.where(eq(pacAuthLinkUserRole.userId, id)); |
||||
const deptList = await this.mysqlService.db |
||||
.select({ |
||||
deptId: pacAuthDept.deptId, |
||||
deptName: pacAuthDept.deptName, |
||||
}) |
||||
.from(pacAuthDept) |
||||
.leftJoin(pacAuthLinkUserDept, eq(pacAuthLinkUserDept.deptId, pacAuthDept.deptId)) |
||||
.where(eq(pacAuthLinkUserDept.userId, id)); |
||||
const postList = await this.mysqlService.db |
||||
.select({ |
||||
postId: pacAuthPost.postId, |
||||
postName: pacAuthPost.postName, |
||||
postKey: pacAuthPost.postKey, |
||||
}) |
||||
.from(pacAuthPost) |
||||
.leftJoin(pacAuthLinkUserPost, eq(pacAuthLinkUserPost.postId, pacAuthPost.postId)) |
||||
.where(eq(pacAuthLinkUserPost.userId, id)); |
||||
return { |
||||
...user[0], |
||||
roleList, |
||||
deptList, |
||||
postList, |
||||
}; |
||||
} |
||||
|
||||
// DB 删除账户
|
||||
private async deleteUser(id: string, userId) { |
||||
const user = await this.mysqlService.db |
||||
.select({ id: pacAuthUser.userId, pid: pacAuthUser.pid }) |
||||
.from(pacAuthUser) |
||||
.where(and(isNull(pacAuthUser.deleteby), eq(pacAuthUser.userId, id))); |
||||
if (user.length == 0) throw new HttpException('未找到目标用户信息,无法删除!', HttpStatus.BAD_REQUEST); |
||||
|
||||
// ! 清理角色菜单关联表
|
||||
await this.mysqlService.db.delete(pacAuthLinkUserRole).where(eq(pacAuthLinkUserRole.userId as any, id)); |
||||
|
||||
// ! 清理部门菜单关联表
|
||||
await this.mysqlService.db.delete(pacAuthLinkUserDept).where(eq(pacAuthLinkUserDept.userId as any, id)); |
||||
|
||||
// ! 清理岗位菜单关联表
|
||||
await this.mysqlService.db.delete(pacAuthLinkUserPost).where(eq(pacAuthLinkUserPost.userId as any, id)); |
||||
|
||||
// ! 判断父节点是否存在
|
||||
if (user[0].pid != 0) { |
||||
// ! 减少父级子节点数量
|
||||
await this.haveChildrenSelfIncreasing(user[0].pid, false); |
||||
} |
||||
|
||||
// ! 删除角色数据
|
||||
return await this.mysqlService.db |
||||
.update(pacAuthUser) |
||||
.set({ |
||||
deletetime: sql`now()`, |
||||
deleteby: userId, |
||||
}) |
||||
.where(eq(pacAuthUser.userId, id)); |
||||
} |
||||
|
||||
// DB 更新账户
|
||||
private async updateUser(id: string, updateAuthUserDto: UpdateAuthUserDto, pacInfo: PacInfoType) { |
||||
const user = await this.mysqlService.db |
||||
.select({ id: pacAuthUser.userId, pid: pacAuthUser.pid }) |
||||
.from(pacAuthUser) |
||||
.where(and(isNull(pacAuthUser.deleteby), eq(pacAuthUser.userId, id))); |
||||
if (user.length == 0) throw new HttpException('未找到目标用户信息,无法修改!', HttpStatus.BAD_REQUEST); |
||||
|
||||
// 用户名不修改不需要查重
|
||||
|
||||
if (updateAuthUserDto.roleList) { |
||||
await this.updateUserRole(id, updateAuthUserDto.roleList, pacInfo); |
||||
} |
||||
if (updateAuthUserDto.deptList) { |
||||
await this.updateUserDept(id, updateAuthUserDto.deptList, pacInfo); |
||||
} |
||||
if (updateAuthUserDto.postList) { |
||||
await this.updateUserPost(id, updateAuthUserDto.postList, pacInfo); |
||||
} |
||||
|
||||
return await this.mysqlService.db |
||||
.update(pacAuthUser) |
||||
.set({ |
||||
nickname: updateAuthUserDto.nickname, |
||||
userType: updateAuthUserDto.userType, |
||||
userEmail: updateAuthUserDto.userEmail, |
||||
avatar: updateAuthUserDto.avatar, |
||||
userPhone: updateAuthUserDto.userPhone, |
||||
userDesc: updateAuthUserDto.userDesc, |
||||
status: updateAuthUserDto.status, |
||||
updateby: pacInfo.userId, |
||||
updatetime: sql`now()`, |
||||
}) |
||||
.where(eq(pacAuthUser.userId, id)); |
||||
} |
||||
|
||||
// DB 修改密码
|
||||
private async resetPassword(id: string, newPassword: string | null) { |
||||
let password = ''; |
||||
if (newPassword != null) { |
||||
password = newPassword; |
||||
} else { |
||||
// ! 从Redis获取默认密码
|
||||
const defaultPasswordForRedis = await this.redisService.get('ENV_DEFAULT_PASSWORD'); |
||||
|
||||
// ? 判断redis中是否存在默认密码环境变量
|
||||
if (!defaultPasswordForRedis) { |
||||
password = this.config.get<string>('system.defaultPassword'); |
||||
} else { |
||||
password = defaultPasswordForRedis; |
||||
} |
||||
} |
||||
|
||||
// ! 加密密码
|
||||
const pass = cryptoPassword(password, this.config.get<number>('system.passwordSalt')); |
||||
|
||||
return await this.mysqlService.db |
||||
.update(pacAuthUser) |
||||
.set({ |
||||
password: pass, |
||||
}) |
||||
.where(eq(pacAuthUser.userId, id)); |
||||
} |
||||
|
||||
// DB 查看目标是否存在
|
||||
private async checkUserExist(id: string) { |
||||
const user = await this.mysqlService.db |
||||
.select({ id: pacAuthUser.userId, pid: pacAuthUser.pid }) |
||||
.from(pacAuthUser) |
||||
.where(and(isNull(pacAuthUser.deleteby), eq(pacAuthUser.userId, id))); |
||||
if (user.length == 0) throw new HttpException('未找到目标用户信息,无法修改!', HttpStatus.BAD_REQUEST); |
||||
return user[0]; |
||||
} |
||||
|
||||
// DB 登陆检测
|
||||
private async signinDetection(usernameSignInDto: UsernameSignInDto) { |
||||
const user = await this.mysqlService.db |
||||
.select({ userId: pacAuthUser.userId, pid: pacAuthUser.pid, password: pacAuthUser.password }) |
||||
.from(pacAuthUser) |
||||
.where(and(isNull(pacAuthUser.deleteby), eq(pacAuthUser.username, usernameSignInDto.username))); |
||||
if (user.length == 0) throw new HttpException('该用户不存在!', HttpStatus.BAD_REQUEST); |
||||
|
||||
// ! 判断是否超过最大登录次数
|
||||
const number = await this.redisService.get('SIGNIN_NUM' + user[0].userId); |
||||
let maxNumberFieldsigninForRedis = (await this.redisService.get('CONFIG_MAX_NUMBER_FIELD_SIGNIN')) as any; |
||||
if (!maxNumberFieldsigninForRedis) { |
||||
maxNumberFieldsigninForRedis = this.config.get<number>('system.signin.maxNumberFieldsignin'); |
||||
} |
||||
if (Number(number) >= maxNumberFieldsigninForRedis) { |
||||
throw new HttpException(`登录错误次数过多:${number}次!`, HttpStatus.BAD_REQUEST); |
||||
} |
||||
|
||||
// ! 验证密码
|
||||
const pass = cryptoPassword(usernameSignInDto.password, this.config.get<number>('system.passwordSalt')); |
||||
if (pass != user[0].password) { |
||||
let maxTimeFieldsignin = (await this.redisService.get('CONFIG_MAX_TIME_FIELD_SIGNIN')) as any; |
||||
if (!maxTimeFieldsignin) { |
||||
maxTimeFieldsignin = this.config.get<number>('system.signin.maxTimeFieldsignin'); |
||||
} |
||||
await this.redisService.redis.SET('SIGNIN_NUM' + user[0].userId, Number(number) ? Number(number) + 1 : 1, { |
||||
PX: maxTimeFieldsignin, |
||||
}); |
||||
throw new HttpException(`用户名或密码错误:${Number(number) + 1}次!`, HttpStatus.BAD_REQUEST); |
||||
} |
||||
|
||||
// ! 判断是否是最大登录数
|
||||
const clientList = await this.redisService.redis.keys('CLIENT-' + user[0].userId + '-*'); |
||||
let maxSigninClient = (await this.redisService.get('CONFIG_MAX_SIGNIN_CLIENT')) as any; |
||||
if (!maxSigninClient) { |
||||
maxSigninClient = this.config.get<number>('system.signin.maxSigninClient'); |
||||
} |
||||
console.log(maxSigninClient, clientList.length >= maxSigninClient) |
||||
if (clientList.length >= maxSigninClient) { |
||||
throw new HttpException('已登陆的客户端超过限制!', HttpStatus.BAD_REQUEST); |
||||
} |
||||
|
||||
// ! 签发Token
|
||||
const token = this.jwt.token({ username: usernameSignInDto.username, userId: user[0].userId, timestamp: new Date().getTime() }); |
||||
const refreshToken = this.jwt.refreshToken({ username: usernameSignInDto.username, userId: user[0].userId, timestamp: new Date().getTime() }); |
||||
|
||||
// 将登陆的账户放进Redis
|
||||
await this.redisService.redis.set('CLIENT-' + user[0].userId + '-' + MD5(refreshToken), 0, { |
||||
EX: this.config.get<number>('system.signin.refreshTokenTime'), |
||||
}); |
||||
await this.redisService.redis.set('CLIENT-ONLINE-' + user[0].userId + '-' + MD5(token), 0, { |
||||
EX: this.config.get<number>('system.signin.refreshTokenTime'), |
||||
}); |
||||
|
||||
return { |
||||
token, |
||||
refreshToken, |
||||
}; |
||||
} |
||||
} |
||||
|
@ -1 +1,161 @@ |
||||
export class CreateAuthUserDto {} |
||||
import { ApiProperty } from '@nestjs/swagger'; |
||||
import Trim from '@common/decorator/trim/trim.decorator'; |
||||
import { ArrayMaxSize, ArrayMinSize, IsOptional, IsString, Length } from 'class-validator'; |
||||
import FormatUsername from "@common/decorator/formatUsername/formatUsername"; |
||||
|
||||
export class CreateAuthUserDto { |
||||
@ApiProperty({ |
||||
description: '账户父ID', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 1, |
||||
maxLength: 32, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '部门关联属性应为字符串格式!' }) |
||||
@IsOptional() |
||||
readonly pid?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '头像', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 1, |
||||
maxLength: 255, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '头像应为字符串格式!' }) |
||||
@Length(1, 255, { message: '请将头像长度控制在1到255位之间!' }) |
||||
@IsOptional() |
||||
readonly avatar?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '昵称', |
||||
type: String, |
||||
example: '研发经理', |
||||
required: true, |
||||
minLength: 1, |
||||
maxLength: 32, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '昵称应为字符串格式!' }) |
||||
@Length(1, 32, { message: '昵称长度控制在1到32位之间!' }) |
||||
readonly nickname: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '岗位Id列表', |
||||
type: [String], |
||||
example: ['a'], |
||||
required: true, |
||||
minItems: 0, |
||||
maxItems: 100, |
||||
}) |
||||
@IsString({ each: true, message: '岗位Id格式错误' }) |
||||
@ArrayMinSize(0, { message: '至少需要选择一个岗位' }) |
||||
@ArrayMaxSize(100, { message: '需要绑定的岗位超过限制' }) |
||||
@Length(19, 19, { each: true, message: '岗位Id格式错误' }) |
||||
@IsOptional() |
||||
readonly postList: string[]; |
||||
|
||||
@ApiProperty({ |
||||
description: '角色Id列表', |
||||
type: [String], |
||||
example: ['a'], |
||||
required: true, |
||||
minItems: 0, |
||||
maxItems: 100, |
||||
}) |
||||
@IsString({ each: true, message: '角色Id格式错误' }) |
||||
@ArrayMinSize(0, { message: '至少需要选择一个角色' }) |
||||
@ArrayMaxSize(100, { message: '需要绑定的角色超过限制' }) |
||||
@Length(19, 19, { each: true, message: '角色Id格式错误' }) |
||||
@IsOptional() |
||||
readonly roleList?: string[]; |
||||
|
||||
@ApiProperty({ |
||||
description: '部门Id列表', |
||||
type: [String], |
||||
example: ['a'], |
||||
required: true, |
||||
minItems: 0, |
||||
maxItems: 100, |
||||
}) |
||||
@IsString({ each: true, message: '部门Id格式错误' }) |
||||
@ArrayMinSize(0, { message: '至少需要选择一个部门' }) |
||||
@ArrayMaxSize(100, { message: '需要绑定的部门超过限制' }) |
||||
@Length(19, 19, { each: true, message: '部门Id格式错误' }) |
||||
@IsOptional() |
||||
readonly deptList: string[]; |
||||
|
||||
@ApiProperty({ |
||||
description: '账户描述', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 1, |
||||
maxLength: 255, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '账户描述应为字符串格式!' }) |
||||
@Length(1, 255, { message: '请将账户描述长度控制在1到255位之间!' }) |
||||
@IsOptional() |
||||
readonly userDesc: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '邮箱', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 5, |
||||
maxLength: 255, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '邮箱应为字符串格式!' }) |
||||
@Length(5, 255, { message: '请将邮箱长度控制在5到255位之间!' }) |
||||
@IsOptional() |
||||
readonly userEmail: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '用户名', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 4, |
||||
maxLength: 128, |
||||
}) |
||||
@Trim() |
||||
@FormatUsername() |
||||
@IsString({ message: '用户名应为字符串格式!' }) |
||||
@Length(4, 128, { message: '请将用户名长度控制在4到128位之间!' }) |
||||
readonly username: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '手机号', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 11, |
||||
maxLength: 11, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '手机号格式不正确!' }) |
||||
@Length(11, 11, { message: '手机号格式不正确!' }) |
||||
@IsOptional() |
||||
readonly userPhone: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '账户类型,来自于字典', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 19, |
||||
maxLength: 19, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '账户类型格式不正确!' }) |
||||
@Length(19, 19, { message: '账户类型格式不正确!' }) |
||||
@IsOptional() |
||||
readonly userType: string; |
||||
} |
||||
|
@ -0,0 +1,175 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: get-auth-role.dto.ts -
|
||||
// | @创建时间: 2024-06-25 17:22
|
||||
// | @更新时间: 2024-06-25 17:22
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import { GetDto } from '@dto/get.dto'; |
||||
import { ApiProperty } from '@nestjs/swagger'; |
||||
import Trim from '@common/decorator/trim/trim.decorator'; |
||||
import { ArrayMaxSize, ArrayMinSize, IsEnum, IsInt, IsOptional, IsString, Length, Max, Min } from 'class-validator'; |
||||
import { BooleanEnum } from '@utils/boolean.enum'; |
||||
import Int from '@common/decorator/int/int.descrator'; |
||||
|
||||
export class GetPacAuthUserAllDto extends GetDto { |
||||
@ApiProperty({ |
||||
description: '账户信息', |
||||
type: String, |
||||
example: '管理员', |
||||
required: false, |
||||
minLength: 1, |
||||
maxLength: 128, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '账户信息应为字符串格式!' }) |
||||
@Length(0, 128, { message: '请将账户信息长度控制在1到128位之间!' }) |
||||
@IsOptional() |
||||
readonly userInfo?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '账户类型,来自于字典', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 19, |
||||
maxLength: 19, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '账户类型格式不正确!' }) |
||||
@Length(19, 19, { message: '账户类型格式不正确!' }) |
||||
@IsOptional() |
||||
readonly userType: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '是否存在子账户', |
||||
type: BooleanEnum, |
||||
enum: BooleanEnum, |
||||
example: 0, |
||||
required: false, |
||||
}) |
||||
@Trim() |
||||
@IsEnum(BooleanEnum, { message: 'haveChildren参数格式错误' }) |
||||
@IsOptional() |
||||
readonly haveChildren: BooleanEnum; |
||||
|
||||
@ApiProperty({ |
||||
description: '账户状态', |
||||
type: Number, |
||||
example: 0, |
||||
required: false, |
||||
minimum: -100, |
||||
maximum: 100, |
||||
}) |
||||
@Trim() |
||||
@Int() |
||||
@IsInt({ |
||||
message: '账户状态必须是整数!', |
||||
}) |
||||
@Min(-100, { |
||||
message: '账户状态需要大于-100!', |
||||
}) |
||||
@Max(100, { |
||||
message: '账户状态不能超过100', |
||||
}) |
||||
@IsOptional() |
||||
readonly status?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '账户层级id', |
||||
type: Number, |
||||
example: 0, |
||||
required: false, |
||||
minimum: 0, |
||||
maximum: 100, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '账户层级id应为字符串格式!' }) |
||||
@Length(1, 20, { message: '账户层级id格式错误!' }) |
||||
@IsOptional() |
||||
readonly hierarchy?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '角色Id', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 19, |
||||
maxLength: 19, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '角色Id类型格式不正确!' }) |
||||
@Length(19, 19, { message: '角色Id类型格式不正确!' }) |
||||
@IsOptional() |
||||
readonly roleId?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '部门Id', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 19, |
||||
maxLength: 19, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '部门Id类型格式不正确!' }) |
||||
@Length(19, 19, { message: '部门Id类型格式不正确!' }) |
||||
@IsOptional() |
||||
readonly deptId?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '岗位Id', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 19, |
||||
maxLength: 19, |
||||
}) |
||||
@Trim() |
||||
@IsString({ message: '岗位Id类型格式不正确!' }) |
||||
@Length(19, 19, { message: '岗位Id类型格式不正确!' }) |
||||
@IsOptional() |
||||
readonly postId?: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '查没有角色的账户', |
||||
type: BooleanEnum, |
||||
enum: BooleanEnum, |
||||
example: 0, |
||||
required: false, |
||||
}) |
||||
@Trim() |
||||
@IsEnum(BooleanEnum, { message: 'noRole参数格式错误' }) |
||||
@IsOptional() |
||||
readonly noRole: BooleanEnum; |
||||
|
||||
@ApiProperty({ |
||||
description: '查没有部门的账户', |
||||
type: BooleanEnum, |
||||
enum: BooleanEnum, |
||||
example: 0, |
||||
required: false, |
||||
}) |
||||
@Trim() |
||||
@IsEnum(BooleanEnum, { message: 'noDept参数格式错误' }) |
||||
@IsOptional() |
||||
readonly noDept: BooleanEnum; |
||||
|
||||
@ApiProperty({ |
||||
description: '查没有岗位的账户', |
||||
type: BooleanEnum, |
||||
enum: BooleanEnum, |
||||
example: 0, |
||||
required: false, |
||||
}) |
||||
@Trim() |
||||
@IsEnum(BooleanEnum, { message: 'noPost参数格式错误' }) |
||||
@IsOptional() |
||||
readonly noPost: BooleanEnum; |
||||
} |
@ -0,0 +1,48 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: password.dto.ts -
|
||||
// | @创建时间: 2024-06-29 22:01
|
||||
// | @更新时间: 2024-06-29 22:01
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import { ApiProperty } from '@nestjs/swagger'; |
||||
import Trim from '@common/decorator/trim/trim.decorator'; |
||||
import FormatUsername from '@common/decorator/formatUsername/formatUsername'; |
||||
import { IsString, Length } from 'class-validator'; |
||||
|
||||
export class PasswordDto { |
||||
@ApiProperty({ |
||||
description: '新密码', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 8, |
||||
maxLength: 128, |
||||
}) |
||||
@Trim() |
||||
@FormatUsername() |
||||
@IsString({ message: '新密码应为字符串格式!' }) |
||||
@Length(8, 128, { message: '请将新密码长度控制在8到128位之间!' }) |
||||
readonly newPassword: string; |
||||
|
||||
|
||||
@ApiProperty({ |
||||
description: '旧密码', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 6, |
||||
maxLength: 128, |
||||
}) |
||||
@Trim() |
||||
@FormatUsername() |
||||
@IsString({ message: '旧密码应为字符串格式!' }) |
||||
@Length(6, 128, { message: '请将旧密码长度控制在6到128位之间!' }) |
||||
readonly oldPassword: string; |
||||
} |
@ -0,0 +1,46 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: signin.dto.ts -
|
||||
// | @创建时间: 2024-06-29 22:30
|
||||
// | @更新时间: 2024-06-29 22:30
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
import { ApiProperty } from '@nestjs/swagger'; |
||||
import Trim from '@common/decorator/trim/trim.decorator'; |
||||
import FormatUsername from '@common/decorator/formatUsername/formatUsername'; |
||||
import { IsString, Length } from 'class-validator'; |
||||
|
||||
export class UsernameSignInDto { |
||||
@ApiProperty({ |
||||
description: '用户名', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 4, |
||||
maxLength: 128, |
||||
}) |
||||
@Trim() |
||||
@FormatUsername() |
||||
@IsString({ message: '用户名应为字符串格式!' }) |
||||
@Length(4, 128, { message: '请将用户名长度控制在4到128位之间!' }) |
||||
readonly username: string; |
||||
|
||||
@ApiProperty({ |
||||
description: '新密码', |
||||
type: String, |
||||
example: '0', |
||||
required: false, |
||||
minLength: 6, |
||||
maxLength: 128, |
||||
}) |
||||
@Trim() |
||||
@FormatUsername() |
||||
@IsString({ message: '新密码应为字符串格式!' }) |
||||
@Length(6, 128, { message: '请将新密码长度控制在6到128位之间!' }) |
||||
readonly password: string; |
||||
} |
@ -1,4 +1,25 @@ |
||||
import { PartialType } from '@nestjs/swagger'; |
||||
import { ApiProperty, PartialType } from '@nestjs/swagger'; |
||||
import { CreateAuthUserDto } from './create-auth-user.dto'; |
||||
import { IsInt, IsOptional, Max, Min } from 'class-validator'; |
||||
|
||||
export class UpdateAuthUserDto extends PartialType(CreateAuthUserDto) {} |
||||
export class UpdateAuthUserDto extends PartialType(CreateAuthUserDto) { |
||||
@ApiProperty({ |
||||
description: '状态', |
||||
type: Number, |
||||
example: 10, |
||||
required: false, |
||||
minimum: -100, |
||||
maximum: 100, |
||||
}) |
||||
@IsOptional() |
||||
@IsInt({ |
||||
message: '状态必须是整数!', |
||||
}) |
||||
@Min(-1000, { |
||||
message: '状态不能小于-100!', |
||||
}) |
||||
@Max(1000, { |
||||
message: '状态不能超过100', |
||||
}) |
||||
readonly status: number; |
||||
} |
||||
|
@ -0,0 +1,31 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: updateLink.dto.ts -
|
||||
// | @创建时间: 2024-06-29 22:07
|
||||
// | @更新时间: 2024-06-29 22:07
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import { ApiProperty } from '@nestjs/swagger'; |
||||
import { ArrayMaxSize, ArrayMinSize, IsString, Length } from 'class-validator'; |
||||
|
||||
export class UpdateLinkDto { |
||||
@ApiProperty({ |
||||
description: 'Id列表', |
||||
type: [String], |
||||
example: ['a'], |
||||
required: true, |
||||
minItems: 0, |
||||
maxItems: 100, |
||||
}) |
||||
@IsString({ each: true, message: 'Id格式错误' }) |
||||
@ArrayMinSize(0, { message: '至少需要选择一个id' }) |
||||
@ArrayMaxSize(100, { message: '需要绑定的id超过限制' }) |
||||
@Length(19, 19, { each: true, message: 'Id格式错误' }) |
||||
readonly list: string[]; |
||||
} |
@ -0,0 +1,26 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: formatUsername.ts -
|
||||
// | @创建时间: 2024-06-29 16:20
|
||||
// | @更新时间: 2024-06-29 16:20
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import { Transform } from 'class-transformer'; |
||||
|
||||
export default function FormatUsername() { |
||||
return Transform(({ value }) => { |
||||
if (typeof value === 'string') { |
||||
if (value.trim() == '') { |
||||
return undefined; |
||||
} |
||||
return value.replace(/\s/g, '').toLowerCase(); |
||||
} |
||||
return value; |
||||
}); |
||||
} |
@ -0,0 +1,28 @@ |
||||
import { Injectable } from '@nestjs/common'; |
||||
import { ConfigService } from '@nestjs/config'; |
||||
import { LoggerService } from '@service/logger/logger.service'; |
||||
import * as jwt from 'jsonwebtoken'; |
||||
|
||||
@Injectable() |
||||
export class JwtService { |
||||
constructor( |
||||
private readonly configService: ConfigService, |
||||
private readonly logger: LoggerService, |
||||
) {} |
||||
|
||||
public token(payload: any): Promise<any> { |
||||
return jwt.sign(payload, this.configService.get<string>('system.signin.secretKey'), { |
||||
expiresIn: this.configService.get<number>('system.signin.tokenTime'), |
||||
}); |
||||
} |
||||
|
||||
public refreshToken(payload: any) { |
||||
return jwt.sign(payload, this.configService.get<string>('system.signin.secretKey'), { |
||||
expiresIn: this.configService.get<number>('system.signin.refreshTokenTime'), |
||||
}); |
||||
} |
||||
|
||||
public verify(token: any) { |
||||
jwt.verify(token, this.configService.get<string>('system.signin.secretKey')); |
||||
} |
||||
} |
@ -1,18 +0,0 @@ |
||||
import { Test, TestingModule } from '@nestjs/testing'; |
||||
import { MysqlService } from './mysql.service'; |
||||
|
||||
describe('MysqlService', () => { |
||||
let service: MysqlService; |
||||
|
||||
beforeEach(async () => { |
||||
const module: TestingModule = await Test.createTestingModule({ |
||||
providers: [MysqlService], |
||||
}).compile(); |
||||
|
||||
service = module.get<MysqlService>(MysqlService); |
||||
}); |
||||
|
||||
it('should be defined', () => { |
||||
expect(service).toBeDefined(); |
||||
}); |
||||
}); |
@ -1,18 +0,0 @@ |
||||
import { Test, TestingModule } from '@nestjs/testing'; |
||||
import { RedisService } from './redis.service'; |
||||
|
||||
describe('RedisService', () => { |
||||
let service: RedisService; |
||||
|
||||
beforeEach(async () => { |
||||
const module: TestingModule = await Test.createTestingModule({ |
||||
providers: [RedisService], |
||||
}).compile(); |
||||
|
||||
service = module.get<RedisService>(RedisService); |
||||
}); |
||||
|
||||
it('should be defined', () => { |
||||
expect(service).toBeDefined(); |
||||
}); |
||||
}); |
@ -1,3 +1,2 @@ |
||||
import { relations } from "drizzle-orm/relations"; |
||||
import { } from "./schema"; |
||||
|
||||
import { relations } from 'drizzle-orm/relations'; |
||||
import {} from './schema'; |
||||
|
@ -0,0 +1,17 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: MD5.ts -
|
||||
// | @创建时间: 2024-06-29 23:50
|
||||
// | @更新时间: 2024-06-29 23:50
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
import * as crypto from 'node:crypto'; |
||||
|
||||
export default function MD5(data) { |
||||
return crypto.createHash('md5').update(data).digest('hex').toUpperCase(); |
||||
} |
@ -0,0 +1,20 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: cryptoPassword.ts -
|
||||
// | @创建时间: 2024-06-29 15:44
|
||||
// | @更新时间: 2024-06-29 15:44
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import * as crypto from 'node:crypto'; |
||||
export default function cryptoPassword(str: string, salt) { |
||||
return crypto |
||||
.createHash('sha256') |
||||
.update(salt + str) |
||||
.digest('hex'); |
||||
} |
@ -0,0 +1,16 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-hotok】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @所在项目: pac-auth
|
||||
// | @文件描述: 密码随机盐.js -
|
||||
// | @创建时间: 2024-06-29 15:46
|
||||
// | @更新时间: 2024-06-29 15:46
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
const crypto = require('crypto'); |
||||
const salt = crypto.randomBytes(16).toString('hex'); |
||||
|
||||
console.log('A', salt); |
Loading…
Reference in new issue