Files
dmenu-api/src/modules/roles/providers/roles.service.ts
T
2025-12-28 10:26:24 +03:30

139 lines
4.4 KiB
TypeScript

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<Role>,
@InjectRepository(Permission)
private readonly permissionRepository: EntityRepository<Permission>,
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<Role> = { $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);
}
}