139 lines
4.4 KiB
TypeScript
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);
|
|
}
|
|
}
|