import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { InjectRepository } from '@mikro-orm/nestjs'; import { EntityRepository, FilterQuery } from '@mikro-orm/core'; import { Role } from '../entities/role.entity'; import { Permission } from '../entities/permission.entity'; import { Restaurant } from '../../restaurants/entities/restaurant.entity'; import { EntityManager } from '@mikro-orm/postgresql'; import { CreateRoleDto } from '../dto/create-role.dto'; import { UpdateRoleDto } from '../dto/update-role.dto'; import { RolePermission } from '../entities/rolePermission.entity'; @Injectable() export class RolesService { constructor( @InjectRepository(Role) private readonly roleRepository: EntityRepository, @InjectRepository(Permission) private readonly permissionRepository: EntityRepository, private readonly em: EntityManager, ) { } async createRestaurantRole(dto: CreateRoleDto, restId: string) { const { name, permissionIds } = dto; // Check if role already exists const existing = await this.roleRepository.findOne({ name, restaurant: restId ? { id: restId } : null }); if (existing) { throw new BadRequestException('Role with this name already exists for the restaurant'); } let restaurant: Restaurant | null = null; if (restId) { restaurant = await this.em.findOne(Restaurant, { id: restId }); if (!restaurant) { throw new NotFoundException('Restaurant not found'); } } const role = this.roleRepository.create({ name, restaurant, isSystem: false, }); // Add permissions if provided if (permissionIds && permissionIds.length > 0) { const permissions = await this.permissionRepository.find({ id: { $in: permissionIds } }); if (permissions.length !== permissionIds.length) { throw new BadRequestException('One or more permissions not found'); } permissions.forEach(p => role.permissions.add(p)); } await this.em.persistAndFlush(role); return role; } async findAllGeneralAndRestaurantRoles(restId: string) { const where: FilterQuery = { $or: [{ restaurant: restId }, { restaurant: null }], isSystem: false }; const roles = await this.roleRepository.find(where, { orderBy: { createdAt: 'desc' }, populate: ['permissions', 'restaurant'], }); return roles; } 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(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'); } if (dto.name) { role.name = dto.name; } if (dto.permissionIds && dto.permissionIds.length >= 0) { // Clear existing permissions and add new ones role.permissions.removeAll(); const permissions = await this.permissionRepository.find({ id: { $in: dto.permissionIds } }); if (permissions.length !== dto.permissionIds.length) { throw new BadRequestException('One or more permissions not found'); } permissions.forEach(p => role.permissions.add(p)); } await this.em.persistAndFlush(role); return role; } async findAllSystemRoles() { const roles = await this.roleRepository.find( { isSystem: true }, { orderBy: { createdAt: 'desc' }, populate: ['permissions', 'restaurant'], }, ); return roles; } 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'); } // 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); } }