diff --git a/src/Gdecorator/userinfoDecorator/userinfoDecorator.decorator.ts b/src/Gdecorator/userinfoDecorator/userinfoDecorator.decorator.ts index 022ad6d..0ae3cc0 100644 --- a/src/Gdecorator/userinfoDecorator/userinfoDecorator.decorator.ts +++ b/src/Gdecorator/userinfoDecorator/userinfoDecorator.decorator.ts @@ -16,6 +16,7 @@ export const UserInfoDecorator = (...args: string[]) => // ? ? export class userinfoDto { uuid: string; + username: string; } // ? ? diff --git a/src/starlight/dto/position.dto.ts b/src/starlight/dto/position.dto.ts index 2a8ed4d..13c6cae 100644 --- a/src/starlight/dto/position.dto.ts +++ b/src/starlight/dto/position.dto.ts @@ -1,4 +1,14 @@ -import { IsNumber, IsString, Length } from 'class-validator'; +import { + ArrayMinSize, + IsArray, + IsNotEmpty, + IsNumber, + IsOptional, + IsString, + Length, +} from 'class-validator'; +import { Transform, Type } from 'class-transformer'; +import { ValidationPipe } from '@nestjs/common'; export class PositionCreateDTO { // @ 父id @@ -18,7 +28,7 @@ export class PositionCreateDTO { // @ 角色标识 @Length(1, 128, { message: '请将角色定位标识长度控制在8到128位之间!' }) @IsString({ message: '角色定位标识应为字符串格式!' }) - index: string; + pointer: string; // @ 描述 @Length(1, 128, { message: '请将角色定位描述长度控制在8到128位之间!' }) @@ -30,3 +40,59 @@ export class PositionCreateDTO { @IsString({ message: '角色定位图标地址应为字符串格式!' }) ico: string; } + +// 删除指定角色 +export class PositionDeleteDTO { + // @ 角色id + + // @Param(new ValidationPipe({ transform: true })) + // @Transform((val) => { + // if (Number(val)) { + // return Number(val); + // } else { + // throw new Error('角色id必须为数字!'); + // } + // }) + // id: number; + @IsNotEmpty({ message: '角色id不可以为空' }) + @ArrayMinSize(1, { message: '角色id至少有一个' }) + // 文档建议如果是字符串的数组,使用字符串约束更好,因为js其实不存在数字数组,字符串数组等 + @Type(() => Number) + // 上面虽然解决了不是字符串的数组的问题,但是如果传进来的是一个字符串呢?这就太tm难了,所以再在编译时检查一下算了吧,运行时不管了 + @IsArray({ message: '角色id必须是一个数组' }) + readonly id: number[]; +} + +// 更新角色信息DTO +export class PositionUpdateDTO extends PositionCreateDTO { + // @ 父id + @IsOptional() + @IsNumber({}, { message: '父id必须为数字!' }) + fatherid: number; + // @ 父id + @IsNumber({}, { message: 'id必须为数字!' }) + id: number; +} + +// 角色列表 +export class PositionListDTO { + // @ 角色列表 + @IsNotEmpty({ message: '角色id不可以为空' }) + @ArrayMinSize(1, { message: '角色id至少有一个' }) + // 文档建议如果是字符串的数组,使用字符串约束更好,因为js其实不存在数字数组,字符串数组等 + @Type(() => Number) + // 上面虽然解决了不是字符串的数组的问题,但是如果传进来的是一个字符串呢?这就太tm难了,所以再在编译时检查一下算了吧,运行时不管了 + @IsArray({ message: '角色id必须是一个数组' }) + readonly positionId: number[]; +} + +// 关联角色定位 +export class PositionRelationDTO extends PositionListDTO { + // @ 用户列表 + @IsNotEmpty({ message: 'uuid不可以为空' }) + @ArrayMinSize(1, { message: 'uuid至少有一个' }) + @IsString({ each: true, message: 'uuid必须为字符串' }) + @Length(32, 32, { each: true, message: 'uuid长度必须为32位' }) + @IsArray({ message: 'uuid必须是一个数组' }) + readonly uuidList: string[]; +} diff --git a/src/starlight/starlight.controller.ts b/src/starlight/starlight.controller.ts index 81b6e92..fdcca1a 100644 --- a/src/starlight/starlight.controller.ts +++ b/src/starlight/starlight.controller.ts @@ -17,6 +17,8 @@ import { Inject, ExecutionContext, createParamDecorator, + ValidationPipe, + Put, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { ApiTags } from '@nestjs/swagger'; @@ -40,7 +42,13 @@ import { SignInPasswdEntryDto, } from '@/starlight/dto/signIn.dto'; import { VerifyGuard } from '@/starlight/verify.guard'; -import { PositionCreateDTO } from '@/starlight/dto/position.dto'; +import { + PositionCreateDTO, + PositionDeleteDTO, + PositionListDTO, + PositionRelationDTO, + PositionUpdateDTO, +} from '@/starlight/dto/position.dto'; // C C // C 类名称: StarlightController @@ -150,7 +158,7 @@ export class StarlightController { //#endregion - //#region + //#region 角色定位 // ? ? // ? 函数名称: positionCreate // ? 函数描述: 创建角色 @@ -164,6 +172,68 @@ export class StarlightController { return this.starlightService.positionCreate(body, userInfo); } + // ? ? + // ? 函数名称: positionAll + // ? 函数描述: 获取所有角色定位信息 + // ? ? + @UseGuards(VerifyGuard) + @Get('position/all') + positionAll(): Promise { + return this.starlightService.positionAll(); + } + + // ? ? + // ? 函数名称: positionDelete + // ? 函数描述: 删除指定角色信息 + // ? ? + @UseGuards(VerifyGuard) + @Delete('position/delete') + positionDelete( + @Body() + body: PositionDeleteDTO, + ): Promise { + return this.starlightService.positionDelete(body); + } + + // ? ? + // ? 函数名称: positionUpdate + // ? 函数描述: 更新指定定位角色信息 + // ? ? + @UseGuards(VerifyGuard) + @Patch('position/update') + positionUpdate(@Body() body: PositionUpdateDTO): Promise { + return this.starlightService.positionUpdate(body); + } + + // ? ? + // ? 函数名称: positionDefault + // ? 函数描述: 设置默认角色 + // ? ? + @UseGuards(VerifyGuard) + @Patch('position/default') + positionDefault(@Body() body: PositionListDTO): Promise { + return this.starlightService.positionDefault(body); + } + + // ? ? + // ? 函数名称: getDefaultPosittion + // ? 函数描述: 获取默认角色 + // ? ? + @Get('/position/default') + getDefaultPosittion(): Promise { + return this.starlightService.getDefaultPosition(); + } + + // ? ? + // ? 函数名称: positionRelationUUID + // ? 函数描述: 关联用户角色定位 + // ? ? + @UseGuards(VerifyGuard) + @Post('position/relation') + positionRelationUUID(@Body() body: PositionRelationDTO): Promise { + return this.starlightService.positionRelationUUID(body); + } + //#endregion //#region 测试 diff --git a/src/starlight/starlight.service.ts b/src/starlight/starlight.service.ts index 4fd2d21..a6377b4 100644 --- a/src/starlight/starlight.service.ts +++ b/src/starlight/starlight.service.ts @@ -13,7 +13,13 @@ import { RegisterEmailSignUpDto, sex, } from './dto/register.dto'; -import { PositionCreateDTO } from './dto/position.dto'; +import { + PositionCreateDTO, + PositionDeleteDTO, + PositionListDTO, + PositionRelationDTO, + PositionUpdateDTO, +} from './dto/position.dto'; import { ConfigService } from '@nestjs/config'; import { GloggerService } from '@/Gservice/GLOGGER/glogger.service'; import { GdatabaseService } from '@/Gservice/GDATABASE/gdatabase.service'; @@ -608,14 +614,455 @@ export class StarlightService { const fatherid = body.fatherid, type = body.type.trim(), name = body.name.trim(), - index = body.index.trim().toLowerCase(), + pointer = body.pointer.trim().toLowerCase(), describe = body.describe.trim(), ico = body.ico.trim(); this.logger.info(userinfo); - this.logger.info(fatherid, type, name, index, describe, ico); - // 查重标识位 - // 写入标识位 - return {}; + this.logger.info(fatherid, type, name, pointer, describe, ico); + // ! 判断父定位是否存在 + if (fatherid != 0) { + try { + const SQL = `SELECT * FROM user_position WHERE id = ? AND is_delete != 1`; + const [rows] = await this.database.DB.execute(SQL, [fatherid]); + this.logger.info(rows); + if (rows.length != 1) { + const message = '未找到父级定位!'; + return { + data: {}, + message, + success: false, + }; + } + } catch (e) { + this.logger.error(e); + const message = '查找定位信息出现错误!'; + return { + data: {}, + message, + success: false, + }; + } + } + // ! 查重标识 + try { + const SQL = `SELECT pointer FROM user_position WHERE pointer = ?`; + const [rows, fault] = await this.database.DB.execute(SQL, [ + pointer, + ]); + if (rows.length > 0) { + const message = '定位标识重复!'; + return { + data: {}, + message, + success: false, + }; + } + } catch (e) { + this.logger.error(e); + const message = '查找定位信息标识重名出现错误!'; + return { + data: {}, + message, + success: false, + }; + } + // ! 判断同级定位是否重名 + try { + const SQL = `SELECT name FROM user_position WHERE fatherid = ? AND is_delete != 1`; + const [rows, fault] = await this.database.DB.execute(SQL, [ + fatherid, + ]); + for (const i of rows) { + if (i.name == name) { + const message = '同级定位重名!'; + return { + data: {}, + message, + success: false, + }; + } + } + } catch (e) { + this.logger.error(e); + const message = '查找定位信息名称重名出现错误!'; + return { + data: {}, + message, + success: false, + }; + } + // ! 写入定位 + try { + const createTime = new Date(); + const SQL = `INSERT INTO user_position (pointer, name, type, position_describe, fatherid, ico, creator, createtime) VALUES (?, ?, ?, ?, ?, ?, ?, ?);`; + const [rows] = await this.database.DB.execute(SQL, [ + pointer, + name, + type, + describe, + fatherid, + ico, + userinfo.uuid, + createTime, + ]); + this.logger.info(rows); + } catch (e) { + this.logger.error(e); + const message = '写入定位信息出现错误!'; + return { + data: {}, + message, + success: false, + }; + } + return { + data: {}, + message: '创建定位成功!', + }; + } + + // ? ? + // ? 函数名称: positionAll + // ? 函数描述: 获取所有角色定位信息 + // ? ? + public async positionAll() { + try { + const SQL = `SELECT * FROM user_position WHERE is_delete != 1`; + const [rows] = await this.database.DB.execute(SQL, []); + const creatorList = {}; + for (const i of rows) { + if (!creatorList[i.creator]) { + // 获取创建角色用户信息 + const getUserDataSQL = `SELECT nickname FROM user_info_extra WHERE uuid = ?`; + const [rows2] = await this.database.DB.execute( + getUserDataSQL, + [i.creator], + ); + creatorList[i.creator] = rows2.slice(-1)[0]; + } + i.creatorData = creatorList[i.creator]; + } + return { + data: rows, + }; + } catch (e) { + const message = '获取角色定位信息失败!'; + this.logger.error({ + message, + data: e, + }); + return { + message, + success: false, + data: {}, + }; + } + } + + // ? ? + // ? 函数名称: positionDelete + // ? 函数描述: 删除指定角色信息 + // ? ? + public async positionDelete(body: PositionDeleteDTO) { + const { id } = body; + const deleteSQL = `UPDATE user_position SET is_delete = 1 WHERE id = ?;`; + const successList = [], + errorList = [], + errorObj = []; + for (const item of id) { + try { + const [row] = await this.database.DB.execute(deleteSQL, [item]); + successList.push(item); + } catch (e) { + errorObj.push(e); + errorList.push(item); + } + } + if (errorList.length > 0) { + this.logger.error({ + message: '删除角色定位失败!', + data: errorObj, + }); + return { + data: {}, + message: '删除角色定位失败!', + success: false, + }; + } + return { + data: {}, + message: '删除角色定位成功!', + success: true, + }; + } + + // ? ? + // ? 函数名称: positionUpdate + // ? 函数描述: 更新指定定位角色信息 + // ? ? + public async positionUpdate(body: PositionUpdateDTO) { + // 去除空格,小写标识位 + const id = body.id, + type = body.type.trim(), + name = body.name.trim(), + pointer = body.pointer.trim().toLowerCase(), + describe = body.describe.trim(), + ico = body.ico.trim(); + // ! 查父id + let fatherid: number; + try { + const SQL = `SELECT fatherid FROM user_position WHERE id = ? AND is_delete != 1`; + const [rows, fault] = await this.database.DB.execute(SQL, [id]); + if (rows.length == 0) { + const message = '未找到该角色定位!'; + return { + message, + data: {}, + success: false, + }; + } else { + fatherid = rows[0].fatherid; + } + } catch (e) { + this.logger.error({ + message: '查找角色父ID失败!', + data: e, + }); + + const message = '查找角色父ID失败!'; + return { + message, + data: {}, + success: false, + }; + } + // ! 查重名和标识 + try { + const checkPointerSQL = `SELECT pointer FROM user_position WHERE pointer = ? AND id != ? AND is_delete != 1`; + const [rows, fault] = await this.database.DB.execute( + checkPointerSQL, + [pointer, id], + ); + if (rows.length != 0) { + const message = '角色定位标识重复!'; + return { + data: {}, + message, + success: false, + }; + } + } catch (e) { + const message = '查冲角色定位标识失败!'; + this.logger.error({ + data: e, + message, + }); + return { + data: {}, + message, + success: false, + }; + } + try { + const checkNameSQL = `SELECT name FROM user_position WHERE name=? AND fatherid = ? AND id != ? AND is_delete != 1`; + const [rows, fault] = await this.database.DB.execute(checkNameSQL, [ + name, + fatherid, + id, + ]); + if (rows.length != 0) { + const message = '角色名称重复!'; + return { + data: {}, + message, + success: false, + }; + } + } catch (e) { + const message = '查冲角色名称失败!'; + this.logger.error({ + data: e, + message, + }); + return { + data: {}, + message, + success: false, + }; + } + // ! 写入 + try { + const SQL = + 'UPDATE user_position SET name = ?, pointer = ?, type = ?, position_describe = ?, ico = ? WHERE id = ?'; + const [rows, fault] = await this.database.DB.execute(SQL, [ + name, + pointer, + type, + describe, + ico, + id, + ]); + } catch (e) { + const message = '更新角色定位信息失败!'; + this.logger.info({ + message, + data: e, + }); + return { + data: {}, + success: false, + message, + }; + } + return { + message: '修改角色定位信息成功!', + success: true, + data: {}, + }; + } + + // ? ? + // ? 函数名称: positionDefault + // ? 函数描述: 设置默认角色 + // ? ? + public async positionDefault(body: PositionListDTO) { + // ! 清空默认设置 + try { + const clearSQL = `UPDATE user_position SET default_position = 0;`; + const [rows, fault] = await this.database.DB.execute(clearSQL, []); + } catch (e) { + const message = '清空默认角色失败!'; + this.logger.info({ + data: e, + message, + }); + return { + data: {}, + message, + success: false, + }; + } + // ! 设置新的默认角色 + const setDefaultSQL = `UPDATE user_position SET default_position = 1 WHERE id = ?;`; + const successList = [], + errorList = [], + errObj = [[]]; + for (const item of body.positionId) { + try { + const [rows, fault] = await this.database.DB.execute( + setDefaultSQL, + [item], + ); + successList.push(item); + } catch (e) { + errorList.push(item); + errObj.push(e); + const message = '设置默认角色失败!'; + this.logger.info({ + data: errObj, + message, + }); + return { + data: {}, + message, + success: false, + }; + } + } + return { + data: {}, + success: true, + message: '设置默认角色成功!', + }; + } + + // ? ? + // ? 函数名称: getDefaultPosittion + // ? 函数描述: 获取默认角色 + // ? ? + public async getDefaultPosition() { + try { + const SQL = `SELECT * FROM user_position WHERE default_position = 1 AND is_delete != 1`; + const [rows, fault] = await this.database.DB.execute(SQL, []); + + return { + data: rows, + message: '获取默认角色信息成功!', + success: true, + }; + } catch (e) { + const message = '获取默认角色信息失败'; + this.logger.error({ + data: e, + message, + }); + return { + message, + success: false, + data: {}, + }; + } + } + + // ? ? + // ? 函数名称: positionRelationUUID + // ? 函数描述: 关联用户角色定位 + // ? ? + public async positionRelationUUID(body: PositionRelationDTO) { + // ! 剔除不存在的用户 + + // ! 删除原有的用户角色定位关联 + const clearSQL = `UPDATE user_position_relation SET is_delete = 1 WHERE uuid = ?`; + for (const item of body.uuidList) { + try { + const [rows, fault] = await this.database.DB.execute(clearSQL, [ + item, + ]); + } catch (e) { + const message = 'ERROR,重大错误,清除用户角色关联失败。'; + this.logger.info({ + message, + data: e, + }); + return { + data: e, + success: false, + message, + }; + } + } + // ! 遍历加入新的角色定位关联 + const createTime = new Date(); + const insertSQL = `INSERT INTO user_position_relation (uuid, position_id, createtime) VALUES ?;`; + for (const item of body.uuidList) { + try { + const insertData = body.positionId.map((i) => [ + item, + i, + createTime, + ]); + this.logger.info(insertData); + const [rows, faault] = await this.database.DB.query(insertSQL, [ + insertData, + ]); + } catch (e) { + const message = 'ERROR,重大错误,关联用户角色定位信息失败!'; + this.logger.info({ + data: e, + message, + }); + return { + data: e, + message, + success: false, + }; + } + } + return { + data: {}, + success: true, + message: '关联用户角色定位成功!', + }; } //#endregion diff --git a/src/starlight/verify.guard.ts b/src/starlight/verify.guard.ts index 1b9e889..293c091 100644 --- a/src/starlight/verify.guard.ts +++ b/src/starlight/verify.guard.ts @@ -27,10 +27,17 @@ export class VerifyGuard implements CanActivate { // this.logger.info(data); if (data.token) { const userinfo: userinfoDto = { - uuid: 'xx', + uuid: data.data.uuid, + username: data.data.username, }; context.switchToHttp().getRequest().userinfo = userinfo; // this.logger.info(request.user); + } else { + throw new UnauthorizedException({ + statusCode: 401, + message: '登陆过期!', + error: 'Forbidden', + }); } // console.log(request); // console.log(request.url);request.headers