add rbac module
This commit is contained in:
parent
fab90132b0
commit
9461fc53f3
@ -18,6 +18,8 @@ import {
|
|||||||
UpdateEvent,
|
UpdateEvent,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
|
import { LoadEvent } from 'typeorm/subscriber/event/LoadEvent';
|
||||||
|
|
||||||
import { Configure } from '@/modules/config/configure';
|
import { Configure } from '@/modules/config/configure';
|
||||||
|
|
||||||
import { app } from '@/modules/core/helpers/app';
|
import { app } from '@/modules/core/helpers/app';
|
||||||
@ -72,7 +74,7 @@ export abstract class BaseSubscriber<T extends ObjectLiteral>
|
|||||||
return this.entity;
|
return this.entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
async afterLoad(entity: any) {
|
async afterLoad(entity: any, event?: LoadEvent<T>) {
|
||||||
if ('parent' in entity && isNil(entity.depth)) {
|
if ('parent' in entity && isNil(entity.depth)) {
|
||||||
entity.depth = 0;
|
entity.depth = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1 @@
|
|||||||
export * from './permission.controller';
|
|
||||||
export * from './role.controller';
|
export * from './role.controller';
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './role.controller';
|
export * from './role.controller';
|
||||||
|
export * from './permission.controller';
|
||||||
|
1
src/modules/user/controllers/manager/index.ts
Normal file
1
src/modules/user/controllers/manager/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './user.controller';
|
102
src/modules/user/controllers/manager/user.controller.ts
Normal file
102
src/modules/user/controllers/manager/user.controller.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
ParseUUIDPipe,
|
||||||
|
Patch,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
SerializeOptions,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
import { DeleteWithTrashDto, RestoreDto } from '@/modules/content/dtos/delete.with.trash.dto';
|
||||||
|
import { PermissionAction } from '@/modules/rbac/constants';
|
||||||
|
import { Permission } from '@/modules/rbac/decorators/permission.decorator';
|
||||||
|
import { PermissionChecker } from '@/modules/rbac/types';
|
||||||
|
import { Depends } from '@/modules/restful/decorators/depend.decorator';
|
||||||
|
import { CreateUserDto, FrontedQueryUserDto, UpdateUserDto } from '@/modules/user/dtos/user.dto';
|
||||||
|
import { UserEntity } from '@/modules/user/entities';
|
||||||
|
import { UserService } from '@/modules/user/services';
|
||||||
|
import { UserModule } from '@/modules/user/user.module';
|
||||||
|
|
||||||
|
const permission: PermissionChecker = async (ab) =>
|
||||||
|
ab.can(PermissionAction.MANAGE, UserEntity.name);
|
||||||
|
|
||||||
|
@ApiTags('用户管理')
|
||||||
|
@Depends(UserModule)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Controller('users')
|
||||||
|
export class UserController {
|
||||||
|
constructor(protected service: UserService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户列表
|
||||||
|
*/
|
||||||
|
@Get()
|
||||||
|
@Permission(permission)
|
||||||
|
@SerializeOptions({ groups: ['user-list'] })
|
||||||
|
async list(@Query() options: FrontedQueryUserDto) {
|
||||||
|
return this.service.list(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户信息
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
@Get(':id')
|
||||||
|
@Permission(permission)
|
||||||
|
@SerializeOptions({ groups: ['user-detail'] })
|
||||||
|
async detail(@Param('id', new ParseUUIDPipe()) id: string) {
|
||||||
|
return this.service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增用户
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
@Post()
|
||||||
|
@Permission(permission)
|
||||||
|
@SerializeOptions({ groups: ['user-detail'] })
|
||||||
|
async store(@Body() data: CreateUserDto) {
|
||||||
|
return this.service.create(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
@Patch()
|
||||||
|
@Permission(permission)
|
||||||
|
@SerializeOptions({ groups: ['user-detail'] })
|
||||||
|
async update(@Body() data: UpdateUserDto) {
|
||||||
|
return this.service.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除用户
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
@Delete()
|
||||||
|
@Permission(permission)
|
||||||
|
@SerializeOptions({ groups: ['user-list'] })
|
||||||
|
async delete(@Body() data: DeleteWithTrashDto) {
|
||||||
|
const { ids, trash } = data;
|
||||||
|
return this.service.delete(ids, trash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量恢复用户
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
@Patch('restore')
|
||||||
|
@Permission(permission)
|
||||||
|
@SerializeOptions({ groups: ['user-list'] })
|
||||||
|
async restore(@Body() data: RestoreDto) {
|
||||||
|
const { ids } = data;
|
||||||
|
return this.service.restore(ids);
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,18 @@
|
|||||||
import {
|
import { Controller, Get, Param, ParseUUIDPipe, Query, SerializeOptions } from '@nestjs/common';
|
||||||
Body,
|
|
||||||
Controller,
|
|
||||||
Delete,
|
|
||||||
Get,
|
|
||||||
Param,
|
|
||||||
ParseUUIDPipe,
|
|
||||||
Patch,
|
|
||||||
Post,
|
|
||||||
SerializeOptions,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
|
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
import { DeleteWithTrashDto, RestoreDto } from '@/modules/content/dtos/delete.with.trash.dto';
|
import { IsNull, Not } from 'typeorm';
|
||||||
|
|
||||||
|
import { SelectTrashMode } from '@/modules/database/constants';
|
||||||
import { Depends } from '@/modules/restful/decorators/depend.decorator';
|
import { Depends } from '@/modules/restful/decorators/depend.decorator';
|
||||||
|
import { UserService } from '@/modules/user/services';
|
||||||
import { UserModule } from '@/modules/user/user.module';
|
import { UserModule } from '@/modules/user/user.module';
|
||||||
|
|
||||||
import { Guest } from '../decorators/guest.decorator';
|
import { Guest } from '../decorators/guest.decorator';
|
||||||
import { CreateUserDto, UpdateUserDto } from '../dtos/user.dto';
|
import { FrontedQueryUserDto } from '../dtos/user.dto';
|
||||||
import { UserService } from '../services/user.service';
|
|
||||||
|
|
||||||
@ApiTags('用户管理')
|
@ApiTags('用户查询')
|
||||||
@Depends(UserModule)
|
@Depends(UserModule)
|
||||||
@Controller('users')
|
@Controller('users')
|
||||||
export class UserController {
|
export class UserController {
|
||||||
@ -32,8 +24,8 @@ export class UserController {
|
|||||||
@Get()
|
@Get()
|
||||||
@Guest()
|
@Guest()
|
||||||
@SerializeOptions({ groups: ['user-list'] })
|
@SerializeOptions({ groups: ['user-list'] })
|
||||||
async list() {
|
async list(@Query() options: FrontedQueryUserDto) {
|
||||||
return this.service.list();
|
return this.service.list({ ...options, trashed: SelectTrashMode.NONE });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,52 +36,6 @@ export class UserController {
|
|||||||
@Guest()
|
@Guest()
|
||||||
@SerializeOptions({ groups: ['user-detail'] })
|
@SerializeOptions({ groups: ['user-detail'] })
|
||||||
async detail(@Param('id', new ParseUUIDPipe()) id: string) {
|
async detail(@Param('id', new ParseUUIDPipe()) id: string) {
|
||||||
return this.service.detail(id);
|
return this.service.detail(id, async (qb) => qb.andWhere({ deletedAt: Not(IsNull()) }));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增用户
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
@Post()
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@SerializeOptions({ groups: ['user-detail'] })
|
|
||||||
async store(@Body() data: CreateUserDto) {
|
|
||||||
return this.service.create(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新用户
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
@Patch()
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@SerializeOptions({ groups: ['user-detail'] })
|
|
||||||
async update(@Body() data: UpdateUserDto) {
|
|
||||||
return this.service.update(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除用户
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
@Delete()
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@SerializeOptions({ groups: ['user-list'] })
|
|
||||||
async delete(@Body() data: DeleteWithTrashDto) {
|
|
||||||
const { ids, trash } = data;
|
|
||||||
return this.service.delete(ids, trash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量恢复用户
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
@Patch('restore')
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@SerializeOptions({ groups: ['user-list'] })
|
|
||||||
async restore(@Body() data: RestoreDto) {
|
|
||||||
const { ids } = data;
|
|
||||||
return this.service.restore(ids);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { PartialType, PickType } from '@nestjs/swagger';
|
import { OmitType, PartialType, PickType } from '@nestjs/swagger';
|
||||||
|
|
||||||
import { IsDefined, IsEnum, IsUUID } from 'class-validator';
|
import { IsDefined, IsEnum, IsOptional, IsUUID } from 'class-validator';
|
||||||
|
|
||||||
import { DtoValidation } from '@/modules/core/decorator/dto.validation.decorator';
|
import { DtoValidation } from '@/modules/core/decorator/dto.validation.decorator';
|
||||||
|
import { IsDataExist } from '@/modules/database/constraints';
|
||||||
|
import { PermissionEntity, RoleEntity } from '@/modules/rbac/entities';
|
||||||
import { PaginateWithTrashedDto } from '@/modules/restful/dtos/paginate-width-trashed.dto';
|
import { PaginateWithTrashedDto } from '@/modules/restful/dtos/paginate-width-trashed.dto';
|
||||||
import { UserOrderType, UserValidateGroup } from '@/modules/user/constants';
|
import { UserOrderType, UserValidateGroup } from '@/modules/user/constants';
|
||||||
import { UserCommonDto } from '@/modules/user/dtos/user.common.dto';
|
import { UserCommonDto } from '@/modules/user/dtos/user.common.dto';
|
||||||
@ -17,7 +19,39 @@ export class CreateUserDto extends PickType(UserCommonDto, [
|
|||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
'phone',
|
'phone',
|
||||||
]) {}
|
]) {
|
||||||
|
/**
|
||||||
|
* 用户关联的角色ID列表
|
||||||
|
*/
|
||||||
|
@IsDataExist(RoleEntity, {
|
||||||
|
each: true,
|
||||||
|
always: true,
|
||||||
|
message: '角色不存在',
|
||||||
|
})
|
||||||
|
@IsUUID(undefined, {
|
||||||
|
each: true,
|
||||||
|
always: true,
|
||||||
|
message: '角色ID格式不正确',
|
||||||
|
})
|
||||||
|
@IsOptional({ always: true })
|
||||||
|
roles?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户直接关联的权限ID列表
|
||||||
|
*/
|
||||||
|
@IsDataExist(PermissionEntity, {
|
||||||
|
each: true,
|
||||||
|
always: true,
|
||||||
|
message: '权限不存在',
|
||||||
|
})
|
||||||
|
@IsUUID(undefined, {
|
||||||
|
each: true,
|
||||||
|
always: true,
|
||||||
|
message: '权限ID格式不正确',
|
||||||
|
})
|
||||||
|
@IsOptional({ always: true })
|
||||||
|
permissions?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新用户
|
* 更新用户
|
||||||
@ -36,9 +70,35 @@ export class UpdateUserDto extends PartialType(CreateUserDto) {
|
|||||||
* 查询用户列表的Query数据验证
|
* 查询用户列表的Query数据验证
|
||||||
*/
|
*/
|
||||||
export class QueryUserDto extends PaginateWithTrashedDto {
|
export class QueryUserDto extends PaginateWithTrashedDto {
|
||||||
|
/**
|
||||||
|
* 角色ID:根据角色来过滤用户
|
||||||
|
*/
|
||||||
|
@IsDataExist(RoleEntity, {
|
||||||
|
message: '角色不存在',
|
||||||
|
})
|
||||||
|
@IsUUID(undefined, { message: '角色ID格式错误' })
|
||||||
|
@IsOptional()
|
||||||
|
role?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限ID:根据权限来过滤用户(权限包含用户关联的所有角色的权限以及直接关联的权限)
|
||||||
|
*/
|
||||||
|
@IsDataExist(PermissionEntity, {
|
||||||
|
message: '权限不存在',
|
||||||
|
})
|
||||||
|
@IsUUID(undefined, { message: '权限ID格式错误' })
|
||||||
|
@IsOptional()
|
||||||
|
permission?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排序规则:可指定用户列表的排序规则,默认为按创建时间降序排序
|
* 排序规则:可指定用户列表的排序规则,默认为按创建时间降序排序
|
||||||
*/
|
*/
|
||||||
@IsEnum(UserOrderType)
|
@IsEnum(UserOrderType)
|
||||||
orderBy?: UserOrderType;
|
orderBy?: UserOrderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端查询用户
|
||||||
|
*/
|
||||||
|
@DtoValidation({ type: 'query' })
|
||||||
|
export class FrontedQueryUserDto extends OmitType(QueryUserDto, ['trashed']) {}
|
||||||
|
@ -7,6 +7,9 @@ export class UserRepository extends BaseRepository<UserEntity> {
|
|||||||
protected _qbName: string = 'user';
|
protected _qbName: string = 'user';
|
||||||
|
|
||||||
buildBaseQuery() {
|
buildBaseQuery() {
|
||||||
return this.createQueryBuilder(this.qbName).orderBy(`${this.qbName}.createdAt`, 'DESC');
|
return this.createQueryBuilder(this.qbName)
|
||||||
|
.orderBy(`${this.qbName}.createdAt`, 'DESC')
|
||||||
|
.leftJoinAndSelect(`${this.qbName}.roles`, 'roles')
|
||||||
|
.leftJoinAndSelect(`${this.qbName}.permissions`, 'permissions');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { RouteOption, TagOption } from '../restful/types';
|
import { RouteOption, TagOption } from '../restful/types';
|
||||||
|
|
||||||
import * as controllers from './controllers';
|
import * as controllers from './controllers';
|
||||||
|
import * as managerControllers from './controllers/manager';
|
||||||
|
|
||||||
export function createUserApi() {
|
export function createUserApi() {
|
||||||
const routes: Record<'app', RouteOption[]> = {
|
const routes: Record<'app' | 'manager', RouteOption[]> = {
|
||||||
app: [
|
app: [
|
||||||
{
|
{
|
||||||
name: 'app.user',
|
name: 'app.user',
|
||||||
@ -11,13 +12,21 @@ export function createUserApi() {
|
|||||||
controllers: Object.values(controllers),
|
controllers: Object.values(controllers),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
manager: [
|
||||||
|
{
|
||||||
|
name: 'app.user',
|
||||||
|
path: 'manager',
|
||||||
|
controllers: Object.values(managerControllers),
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const tags: Record<'app', (string | TagOption)[]> = {
|
const tags: Record<'app' | 'manager', (string | TagOption)[]> = {
|
||||||
app: [
|
app: [
|
||||||
{ name: '用户管理', description: '对用户进行CRUD操作' },
|
{ name: '用户管理', description: '对用户进行CRUD操作' },
|
||||||
{ name: '账户操作', description: '注册登录、查看修改账户信息、修改密码等' },
|
{ name: '账户操作', description: '注册登录、查看修改账户信息、修改密码等' },
|
||||||
],
|
],
|
||||||
|
manager: [{ name: '用户管理', description: '管理用户信息' }],
|
||||||
};
|
};
|
||||||
|
|
||||||
return { routes, tags };
|
return { routes, tags };
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
import { isNil } from 'lodash';
|
import { isArray, isNil } from 'lodash';
|
||||||
import { DataSource, EntityNotFoundError, SelectQueryBuilder } from 'typeorm';
|
import { DataSource, EntityNotFoundError, SelectQueryBuilder } from 'typeorm';
|
||||||
|
|
||||||
import { Configure } from '@/modules/config/configure';
|
import { Configure } from '@/modules/config/configure';
|
||||||
@ -8,6 +8,8 @@ import { BaseService } from '@/modules/database/base/service';
|
|||||||
|
|
||||||
import { QueryHook } from '@/modules/database/types';
|
import { QueryHook } from '@/modules/database/types';
|
||||||
|
|
||||||
|
import { SystemRoles } from '@/modules/rbac/constants';
|
||||||
|
import { RoleRepository } from '@/modules/rbac/repositories';
|
||||||
import { UserRepository } from '@/modules/user/repositories';
|
import { UserRepository } from '@/modules/user/repositories';
|
||||||
|
|
||||||
import { CreateUserDto, QueryUserDto, UpdateUserDto } from '../dtos/user.dto';
|
import { CreateUserDto, QueryUserDto, UpdateUserDto } from '../dtos/user.dto';
|
||||||
@ -21,26 +23,68 @@ export class UserService extends BaseService<UserEntity, UserRepository> {
|
|||||||
protected configure: Configure,
|
protected configure: Configure,
|
||||||
protected dataSource: DataSource,
|
protected dataSource: DataSource,
|
||||||
protected userRepository: UserRepository,
|
protected userRepository: UserRepository,
|
||||||
|
protected roleRepository: RoleRepository,
|
||||||
) {
|
) {
|
||||||
super(userRepository);
|
super(userRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建用户
|
* 创建用户
|
||||||
|
* @param roles
|
||||||
|
* @param permissions
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
async create(data: CreateUserDto): Promise<UserEntity> {
|
async create({ roles, permissions, ...data }: CreateUserDto): Promise<UserEntity> {
|
||||||
const user = await this.userRepository.save(data, { reload: true });
|
const user = await this.userRepository.save(data, { reload: true });
|
||||||
|
if (isArray(roles) && roles.length > 0) {
|
||||||
|
await this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.relation('roles')
|
||||||
|
.of(user)
|
||||||
|
.add(roles);
|
||||||
|
}
|
||||||
|
if (isArray(permissions) && permissions.length > 0) {
|
||||||
|
await this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.relation('permissions')
|
||||||
|
.of(user)
|
||||||
|
.add(permissions);
|
||||||
|
}
|
||||||
|
await this.addUserRole(await this.detail(user.id));
|
||||||
return this.detail(user.id);
|
return this.detail(user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新用户
|
* 更新用户
|
||||||
|
* @param roles
|
||||||
|
* @param permissions
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
async update(data: UpdateUserDto): Promise<UserEntity> {
|
async update({ roles, permissions, ...data }: UpdateUserDto): Promise<UserEntity> {
|
||||||
const updated = await this.userRepository.save(data, { reload: true });
|
const updated = await this.userRepository.save(data, { reload: true });
|
||||||
return this.detail(updated.id);
|
const user = await this.detail(updated.id);
|
||||||
|
if (
|
||||||
|
(isNil(roles) || roles.length <= 0) &&
|
||||||
|
(isNil(permissions) || permissions.length <= 0)
|
||||||
|
) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
if (isArray(roles) && roles.length > 0) {
|
||||||
|
await this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.relation('roles')
|
||||||
|
.of(user)
|
||||||
|
.addAndRemove(roles, user.roles ?? []);
|
||||||
|
}
|
||||||
|
if (isArray(permissions) && permissions.length > 0) {
|
||||||
|
await this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.relation('permissions')
|
||||||
|
.of(user)
|
||||||
|
.addAndRemove(permissions, user.permissions ?? []);
|
||||||
|
}
|
||||||
|
await this.addUserRole(await this.detail(user.id));
|
||||||
|
return this.detail(user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,9 +131,32 @@ export class UserService extends BaseService<UserEntity, UserRepository> {
|
|||||||
) {
|
) {
|
||||||
const { orderBy } = options;
|
const { orderBy } = options;
|
||||||
const qb = await super.buildListQB(queryBuilder, options, callback);
|
const qb = await super.buildListQB(queryBuilder, options, callback);
|
||||||
|
if (!isNil(options.role)) {
|
||||||
|
qb.andWhere('roles.id IN (:...roles', { roles: [options.role] });
|
||||||
|
}
|
||||||
|
if (!isNil(options.permission)) {
|
||||||
|
qb.andWhere('permissions.id IN (:...permissions', {
|
||||||
|
permissions: [options.permission],
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!isNil(orderBy)) {
|
if (!isNil(orderBy)) {
|
||||||
qb.orderBy(`${this.repository.qbName}.${orderBy}`, 'ASC');
|
qb.orderBy(`${this.repository.qbName}.${orderBy}`, 'ASC');
|
||||||
}
|
}
|
||||||
return qb;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async addUserRole(user: UserEntity) {
|
||||||
|
const roleRelation = this.userRepository.createQueryBuilder().relation('roles').of(user);
|
||||||
|
const roleNames = (user.roles ?? []).map((role) => role.name);
|
||||||
|
const noneUserRole = roleNames.length <= 0 || !roleNames.includes(SystemRoles.USER);
|
||||||
|
if (noneUserRole) {
|
||||||
|
const userRole = await this.roleRepository.findOne({
|
||||||
|
relations: ['users'],
|
||||||
|
where: { name: SystemRoles.USER },
|
||||||
|
});
|
||||||
|
if (!isNil(userRole)) {
|
||||||
|
await roleRelation.add(userRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { randomBytes } from 'node:crypto';
|
import { randomBytes } from 'node:crypto';
|
||||||
|
|
||||||
import { EventSubscriber, InsertEvent, UpdateEvent } from 'typeorm';
|
import { EventSubscriber, InsertEvent, LoadEvent, UpdateEvent } from 'typeorm';
|
||||||
|
|
||||||
import { BaseSubscriber } from '@/modules/database/base/subscriber';
|
import { BaseSubscriber } from '@/modules/database/base/subscriber';
|
||||||
|
import { RoleEntity } from '@/modules/rbac/entities';
|
||||||
import { UserEntity } from '@/modules/user/entities/user.entity';
|
import { UserEntity } from '@/modules/user/entities/user.entity';
|
||||||
import { encrypt } from '@/modules/user/utils';
|
import { encrypt } from '@/modules/user/utils';
|
||||||
|
|
||||||
@ -36,4 +37,21 @@ export class UserSubscriber extends BaseSubscriber<UserEntity> {
|
|||||||
event.entity.password = await encrypt(this.configure, event.entity.password);
|
event.entity.password = await encrypt(this.configure, event.entity.password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async afterLoad(user: UserEntity, event: LoadEvent<any>): Promise<void> {
|
||||||
|
let permissions = user.permissions ?? [];
|
||||||
|
for (const role of user.roles ?? []) {
|
||||||
|
const roleEntity = await this.getManage(event).findOneOrFail(RoleEntity, {
|
||||||
|
relations: ['permissions'],
|
||||||
|
where: { id: role.id },
|
||||||
|
});
|
||||||
|
permissions = [...permissions, ...(roleEntity.permissions ?? [])];
|
||||||
|
}
|
||||||
|
user.permissions = permissions.reduce((o, n) => {
|
||||||
|
if (o.find(({ name }) => name === n.name)) {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
return [...o, n];
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user