152 lines
4.8 KiB
TypeScript
152 lines
4.8 KiB
TypeScript
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
|
import { InjectRepository } from '@mikro-orm/nestjs';
|
|
import { EntityRepository } 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 { FindRolesDto } from '../dto/find-roles.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 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 });
|
|
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,
|
|
title,
|
|
restaurant,
|
|
});
|
|
|
|
// 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 findAll(restId: string, dto: FindRolesDto) {
|
|
const { name, page = 1, limit = 20 } = dto;
|
|
const offset = (page - 1) * limit;
|
|
|
|
// Build query dynamically
|
|
const query: Record<string, unknown> = restId ? { restaurant: { id: restId } } : {};
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
const [roles, count] = await this.roleRepository.findAndCount(query as any, {
|
|
offset,
|
|
limit,
|
|
populate: ['permissions', 'restaurant'],
|
|
});
|
|
|
|
// Filter by name or title in memory if provided
|
|
let filtered = roles;
|
|
if (name) {
|
|
filtered = roles.filter(
|
|
r => r.name.toLowerCase().includes(name.toLowerCase()) || r.title.toLowerCase().includes(name.toLowerCase()),
|
|
);
|
|
}
|
|
|
|
return {
|
|
data: filtered,
|
|
total: count,
|
|
page,
|
|
limit,
|
|
totalPages: Math.ceil(count / limit),
|
|
};
|
|
}
|
|
|
|
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.title) {
|
|
role.title = dto.title;
|
|
}
|
|
|
|
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 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);
|
|
}
|
|
}
|