From b9d090457744c36a0323ca64380277512ffbd44a Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Tue, 18 Nov 2025 23:11:45 +0330 Subject: [PATCH] Refactor RolesController and RolesService to include restaurant-specific handling by adding RestId parameter to relevant methods; remove optional restaurant ID properties from DTOs for cleaner design; implement soft delete logic in remove method to ensure proper role management. --- src/modules/roles/dto/create-role.dto.ts | 4 -- src/modules/roles/dto/find-roles.dto.ts | 5 --- .../roles/entities/rolePermission.entity.ts | 1 - src/modules/roles/providers/roles.service.ts | 41 +++++++++++++------ src/modules/roles/roles.controller.ts | 23 ++++++----- 5 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/modules/roles/dto/create-role.dto.ts b/src/modules/roles/dto/create-role.dto.ts index 81c5824..46c3cc0 100644 --- a/src/modules/roles/dto/create-role.dto.ts +++ b/src/modules/roles/dto/create-role.dto.ts @@ -12,10 +12,6 @@ export class CreateRoleDto { @IsString() title!: string; - @ApiProperty({ description: 'Restaurant id (optional)', required: false }) - @IsOptional() - @IsString() - restId?: string; @ApiProperty({ description: 'List of permission IDs', isArray: true, required: false }) @IsOptional() diff --git a/src/modules/roles/dto/find-roles.dto.ts b/src/modules/roles/dto/find-roles.dto.ts index 2088ca7..767402b 100644 --- a/src/modules/roles/dto/find-roles.dto.ts +++ b/src/modules/roles/dto/find-roles.dto.ts @@ -8,11 +8,6 @@ export class FindRolesDto { @IsString() name?: string; - @ApiProperty({ description: 'Restaurant id filter', required: false }) - @IsOptional() - @IsString() - restId?: string; - @ApiProperty({ description: 'Page number', required: false, default: 1 }) @IsOptional() @Type(() => Number) diff --git a/src/modules/roles/entities/rolePermission.entity.ts b/src/modules/roles/entities/rolePermission.entity.ts index 75d062d..a99538a 100644 --- a/src/modules/roles/entities/rolePermission.entity.ts +++ b/src/modules/roles/entities/rolePermission.entity.ts @@ -1,4 +1,3 @@ -// role-permission.entity.ts (pivot) import { Entity, ManyToOne } from '@mikro-orm/core'; import { Role } from './role.entity'; import { Permission } from './permission.entity'; diff --git a/src/modules/roles/providers/roles.service.ts b/src/modules/roles/providers/roles.service.ts index a506db9..2edc264 100644 --- a/src/modules/roles/providers/roles.service.ts +++ b/src/modules/roles/providers/roles.service.ts @@ -8,6 +8,7 @@ import { EntityManager } from '@mikro-orm/postgresql'; import { CreateRoleDto } from '../dto/create-role.dto'; import { UpdateRoleDto } from '../dto/update-role.dto'; import { FindRolesDto } from '../dto/find-roles.dto'; +import { RolePermission } from '../entities/rolePermission.entity'; @Injectable() export class RolesService { @@ -19,8 +20,8 @@ export class RolesService { private readonly em: EntityManager, ) {} - async create(dto: CreateRoleDto) { - const { name, title, restId, permissionIds } = dto; + async create(restId: string, dto: CreateRoleDto) { + const { name, title, permissionIds } = dto; // Check if role already exists const existing = await this.roleRepository.findOne({ name, restaurant: restId ? { id: restId } : null }); @@ -55,8 +56,8 @@ export class RolesService { return role; } - async findAll(dto: FindRolesDto) { - const { name, restId, page = 1, limit = 20 } = dto; + async findAll(restId: string, dto: FindRolesDto) { + const { name, page = 1, limit = 20 } = dto; const offset = (page - 1) * limit; // Build query dynamically @@ -86,16 +87,22 @@ export class RolesService { }; } - async findOne(id: string) { - const role = await this.roleRepository.findOne({ id }, { populate: ['permissions', 'restaurant'] }); + async findOne(restId: string, id: string) { + const role = await this.roleRepository.findOne( + { id, restaurant: { id: restId } }, + { populate: ['permissions', 'restaurant'] }, + ); if (!role) { throw new NotFoundException('Role not found'); } return role; } - async update(id: string, dto: UpdateRoleDto) { - const role = await this.roleRepository.findOne({ id }); + async update(restId: string, id: string, dto: UpdateRoleDto) { + const role = await this.roleRepository.findOne( + { id, restaurant: { id: restId } }, + { populate: ['permissions', 'restaurant'] }, + ); if (!role) { throw new NotFoundException('Role not found'); } @@ -122,13 +129,23 @@ export class RolesService { return role; } - async remove(id: string) { - const role = await this.roleRepository.findOne({ id }); + async remove(restId: string, id: string) { + const role = await this.roleRepository.findOne( + { id, restaurant: { id: restId } }, + { populate: ['permissions', 'restaurant'] }, + ); if (!role) { throw new NotFoundException('Role not found'); } + if (!role.admins.isEmpty()) { + throw new BadRequestException('Role has admins'); + } - await this.roleRepository.nativeUpdate({ id }, { deletedAt: new Date() }); - return { message: 'Role deleted successfully' }; + // Hard delete pivot table entries (role_permissions) before soft deleting the role + await this.em.nativeDelete(RolePermission, { role: { id: role.id } }); + + // Soft delete the role + role.deletedAt = new Date(); + return this.em.persistAndFlush(role); } } diff --git a/src/modules/roles/roles.controller.ts b/src/modules/roles/roles.controller.ts index a1b1d6e..118864f 100644 --- a/src/modules/roles/roles.controller.ts +++ b/src/modules/roles/roles.controller.ts @@ -7,6 +7,7 @@ import { UpdateRoleDto } from './dto/update-role.dto'; import { FindRolesDto } from './dto/find-roles.dto'; import { AdminAuthGuard } from '../auth/guards/adminAuth.guard'; import { Permissions } from '../auth/decorators/permissions.decorator'; +import { RestId } from 'src/common/decorators'; @UseGuards(AdminAuthGuard) @ApiBearerAuth() @@ -21,14 +22,14 @@ export class RolesController { @Get() @ApiOperation({ summary: 'Get all roles with pagination and filters' }) @ApiResponse({ status: 200, description: 'Roles retrieved successfully' }) - async findAll(@Query() dto: FindRolesDto) { - return this.roleService.findAll(dto); + findAll(@Query() dto: FindRolesDto, @RestId() restId: string) { + return this.roleService.findAll(restId, dto); } @Get('permissions') @ApiOperation({ summary: 'Get all permissions' }) @ApiResponse({ status: 200, description: 'Permissions retrieved successfully' }) - async findAllPermissions() { + findAllPermissions() { return this.permissionService.findAll(); } @@ -37,16 +38,16 @@ export class RolesController { @ApiOperation({ summary: 'Create a new role' }) @ApiBody({ type: CreateRoleDto }) @ApiResponse({ status: 201, description: 'Role created successfully' }) - async create(@Body() dto: CreateRoleDto) { - return this.roleService.create(dto); + create(@Body() dto: CreateRoleDto, @RestId() restId: string) { + return this.roleService.create(restId, dto); } @Get(':id') @ApiOperation({ summary: 'Get a specific role by ID' }) @ApiResponse({ status: 200, description: 'Role retrieved successfully' }) @ApiResponse({ status: 404, description: 'Role not found' }) - async findOne(@Param('id') id: string) { - return this.roleService.findOne(id); + findOne(@Param('id') id: string, @RestId() restId: string) { + return this.roleService.findOne(restId, id); } @Patch(':id') @@ -54,15 +55,15 @@ export class RolesController { @ApiBody({ type: UpdateRoleDto }) @ApiResponse({ status: 200, description: 'Role updated successfully' }) @ApiResponse({ status: 404, description: 'Role not found' }) - async update(@Param('id') id: string, @Body() dto: UpdateRoleDto) { - return this.roleService.update(id, dto); + update(@Param('id') id: string, @Body() dto: UpdateRoleDto, @RestId() restId: string) { + return this.roleService.update(restId, id, dto); } @Delete(':id') @ApiOperation({ summary: 'Delete a role' }) @ApiResponse({ status: 200, description: 'Role deleted successfully' }) @ApiResponse({ status: 404, description: 'Role not found' }) - async remove(@Param('id') id: string) { - return this.roleService.remove(id); + remove(@Param('id') id: string, @RestId() restId: string) { + return this.roleService.remove(restId, id); } }