diff --git a/src/modules/rbac/constants.ts b/src/modules/rbac/constants.ts index 3b40221..4921d50 100644 --- a/src/modules/rbac/constants.ts +++ b/src/modules/rbac/constants.ts @@ -14,4 +14,4 @@ export enum PermissionAction { DELETE = 'delete', MANAGE = 'manage', OWNER = 'onwer', -} \ No newline at end of file +} diff --git a/src/modules/rbac/controllers/index.ts b/src/modules/rbac/controllers/index.ts new file mode 100644 index 0000000..315007d --- /dev/null +++ b/src/modules/rbac/controllers/index.ts @@ -0,0 +1,2 @@ +export * from './permission.controller'; +export * from './role.controller'; diff --git a/src/modules/rbac/controllers/manager/index.ts b/src/modules/rbac/controllers/manager/index.ts new file mode 100644 index 0000000..fa5a3e4 --- /dev/null +++ b/src/modules/rbac/controllers/manager/index.ts @@ -0,0 +1 @@ +export * from './role.controller'; diff --git a/src/modules/rbac/controllers/manager/role.controller.ts b/src/modules/rbac/controllers/manager/role.controller.ts new file mode 100644 index 0000000..b17eaf6 --- /dev/null +++ b/src/modules/rbac/controllers/manager/role.controller.ts @@ -0,0 +1,82 @@ +import { Body, Controller, Delete, Patch, Post, 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 { RoleEntity } from '@/modules/rbac/entities'; +import { RbacModule } from '@/modules/rbac/rbac.module'; +import { RoleService } from '@/modules/rbac/services'; +import { PermissionChecker } from '@/modules/rbac/types'; +import { Depends } from '@/modules/restful/decorators/depend.decorator'; + +import { Permission } from '../../decorators/permission.decorator'; +import { CreateRoleDto, UpdateRoleDto } from '../../dtos/role.dtos'; + +const permission: PermissionChecker = async (ab) => + ab.can(PermissionAction.MANAGE, RoleEntity.name); + +@ApiTags('角色管理') +@ApiBearerAuth() +@Depends(RbacModule) +@Controller('roles') +export class RoleController { + constructor(private service: RoleService) {} + + /** + * 新增角色 + * @param data + */ + @Post() + @SerializeOptions({ groups: ['role-detail'] }) + @Permission(permission) + async store( + @Body() + data: CreateRoleDto, + ) { + return this.service.create(data); + } + + /** + * 更新角色 + * @param data + */ + @Patch() + @SerializeOptions({ groups: ['role-detail'] }) + @Permission(permission) + async update( + @Body() + data: UpdateRoleDto, + ) { + return this.service.update(data); + } + + /** + * 批量删除角色 + * @param data + */ + @Delete() + @SerializeOptions({ groups: ['role-list'] }) + @Permission(permission) + async delete( + @Body() + data: DeleteWithTrashDto, + ) { + const { ids, trash } = data; + return this.service.delete(ids, trash); + } + + /** + * 批量恢复角色 + * @param data + */ + @Patch('restore') + @SerializeOptions({ groups: ['role-list'] }) + @Permission(permission) + async restore( + @Body() + data: RestoreDto, + ) { + const { ids } = data; + return this.service.restore(ids); + } +} diff --git a/src/modules/rbac/controllers/permission.controller.ts b/src/modules/rbac/controllers/permission.controller.ts new file mode 100644 index 0000000..dc3515c --- /dev/null +++ b/src/modules/rbac/controllers/permission.controller.ts @@ -0,0 +1,47 @@ +import { Controller, Get, Param, ParseUUIDPipe, Query, SerializeOptions } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; + +import { PermissionAction } from '@/modules/rbac/constants'; +import { Permission } from '@/modules/rbac/decorators/permission.decorator'; +import { PermissionEntity } from '@/modules/rbac/entities'; +import { RbacModule } from '@/modules/rbac/rbac.module'; +import { PermissionService } from '@/modules/rbac/services'; +import { PermissionChecker } from '@/modules/rbac/types'; +import { Depends } from '@/modules/restful/decorators/depend.decorator'; +import { PaginateWithTrashedDto } from '@/modules/restful/dtos/paginate-width-trashed.dto'; + +const permission: PermissionChecker = async (ab) => + ab.can(PermissionAction.MANAGE, PermissionEntity.name); + +@ApiTags('权限查询') +@ApiBearerAuth() +@Depends(RbacModule) +@Controller('permissions') +export class PermissionController { + constructor(private service: PermissionService) {} + + permission: PermissionChecker = async (ab) => + ab.can(PermissionAction.MANAGE, PermissionEntity.name); + + /** + * 分页列表查询 + * @param options + */ + @Get() + @SerializeOptions({ groups: ['permission-list'] }) + @Permission(permission) + async list(@Query() options: PaginateWithTrashedDto) { + return this.service.paginate(options); + } + + /** + * 分页列表查询 + * @param id + */ + @Get(':id') + @SerializeOptions({ groups: ['permission-detail'] }) + @Permission(permission) + async detail(@Param('id', new ParseUUIDPipe()) id: string) { + return this.service.detail(id); + } +} diff --git a/src/modules/rbac/controllers/role.controller.ts b/src/modules/rbac/controllers/role.controller.ts new file mode 100644 index 0000000..3058064 --- /dev/null +++ b/src/modules/rbac/controllers/role.controller.ts @@ -0,0 +1,37 @@ +import { Controller, Get, Param, ParseUUIDPipe, Query, SerializeOptions } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; + +import { RbacModule } from '@/modules/rbac/rbac.module'; +import { RoleService } from '@/modules/rbac/services'; +import { Depends } from '@/modules/restful/decorators/depend.decorator'; +import { PaginateWithTrashedDto } from '@/modules/restful/dtos/paginate-width-trashed.dto'; +import { Guest } from '@/modules/user/decorators/guest.decorator'; + +@ApiTags('角色查询') +@Depends(RbacModule) +@Controller('roles') +export class RoleController { + constructor(private service: RoleService) {} + + /** + * 角色列表查询 + * @param options + */ + @Get() + @SerializeOptions({ groups: ['role-list'] }) + @Guest() + async list(@Query() options: PaginateWithTrashedDto) { + return this.service.paginate(options); + } + + /** + * 角色详解查询 + * @param id + */ + @Get(':id') + @SerializeOptions({ groups: ['role-detail'] }) + @Guest() + async detail(@Param('id', new ParseUUIDPipe()) id: string) { + return this.service.detail(id); + } +} diff --git a/src/modules/rbac/decorators/permission.decorator.ts b/src/modules/rbac/decorators/permission.decorator.ts index dc633b6..83c58be 100644 --- a/src/modules/rbac/decorators/permission.decorator.ts +++ b/src/modules/rbac/decorators/permission.decorator.ts @@ -3,5 +3,5 @@ import { SetMetadata } from '@nestjs/common'; import { PERMISSION_CHECKERS } from '../constants'; import { PermissionChecker } from '../types'; -export const Permision = (...checkers: PermissionChecker[]) => +export const Permission = (...checkers: PermissionChecker[]) => SetMetadata(PERMISSION_CHECKERS, checkers); diff --git a/src/modules/rbac/routes.ts b/src/modules/rbac/routes.ts new file mode 100644 index 0000000..19c3a81 --- /dev/null +++ b/src/modules/rbac/routes.ts @@ -0,0 +1,31 @@ +import { RouteOption, TagOption } from '@/modules/restful/types'; + +import * as controllers from './controllers'; +import * as manageControllers from './controllers/manager'; + +export const createRbacApi = () => { + const routes: Record<'app' | 'manage', RouteOption[]> = { + app: [ + { + name: 'app.rbac', + path: 'rbac', + controllers: Object.values(controllers), + }, + ], + manage: [ + { + name: 'manage.rbac', + path: 'rbac', + controllers: Object.values(manageControllers), + }, + ], + }; + const tags: Record<'app' | 'manage', Array> = { + app: [{ name: '角色查询', description: '查询角色信息' }], + manage: [ + { name: '角色管理', description: '管理角色信息' }, + { name: '权限信息', description: '查询权限信息' }, + ], + }; + return { routes, tags }; +}; diff --git a/src/modules/rbac/types.ts b/src/modules/rbac/types.ts index 198b97e..4e4027b 100644 --- a/src/modules/rbac/types.ts +++ b/src/modules/rbac/types.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-extraneous-dependencies */ import { AbilityTuple, MongoAbility, MongoQuery, RawRuleFrom } from '@casl/ability'; import { ModuleRef } from '@nestjs/core'; diff --git a/src/modules/user/services/auth.service.ts b/src/modules/user/services/auth.service.ts index f8cf5f8..9ee41c2 100644 --- a/src/modules/user/services/auth.service.ts +++ b/src/modules/user/services/auth.service.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-extraneous-dependencies */ import { ForbiddenException, Injectable } from '@nestjs/common'; import { FastifyRequest as Request } from 'fastify';