import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { EntityServiceImpl } from '../../meta/service/entity-service-impl.service'; import { BaseEntity } from '../../meta/entity/base-entity.entity'; import { UserData } from '../entity/user.entity'; import { Role } from '../entity/role.entity'; import { ENTITYTYPE_ROLE, STATUS_INACTIVE } from 'src/constant/global.constant'; import { RoleRepository } from '../repository/role.repository'; import { EntityManager, Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { ModuleAccess } from '../../module/entity/module-access.entity'; import { ServiceResult } from 'src/dtos/response'; import { ListMasterService } from 'src/module/listmaster/service/list-master.service'; import { UserRoleMappingRepository } from '../repository/user-role-mapping.repository'; import { UserRoleMapping } from '../entity/user-role-mapping.entity'; @Injectable() export class RoleService extends EntityServiceImpl { constructor( private readonly roleRepository: RoleRepository, private readonly entityManager: EntityManager, @InjectRepository(ModuleAccess) private readonly moduleAccessRepo: Repository, @Inject('ListMasterService') private readonly listMasterService: ListMasterService, @InjectRepository(UserRoleMapping) private readonly userRoleMappingRepo: Repository, ) { super(); } async createEntity( entityData: BaseEntity, loggedInUser: UserData, ): Promise> { const role = entityData as Role; // if level_type and level_id are not provided, use loggedInUser's values role.level_type = entityData.level_type || loggedInUser.level_type; role.level_id = entityData.level_id || loggedInUser.level_id; role.appcode = entityData.appcode || loggedInUser.appcode; if ( await this.roleRepository.isRoleNameWithLevelExists(role.name, { organization_id: loggedInUser?.organization_id || undefined, level_type: entityData.level_type || loggedInUser?.level_type, level_id: parseInt(entityData.level_id) || parseInt(loggedInUser?.level_id || '', 10), }) ) { return { success: false, error: 'Role name already exists.' }; } const sourceRole = role.copy_from_role_id ? await this.getEntityData( ENTITYTYPE_ROLE, role.copy_from_role_id, loggedInUser, ) : null; if (role.copy_from_role_id && !sourceRole) { return { success: false, error: 'Source role not found.' }; } const savedRole = await super.createEntity(role, loggedInUser); if (sourceRole) { const sourcePermissions = await this.moduleAccessRepo.find({ where: { role_code: sourceRole.code }, }); const clonedPermissions = sourcePermissions.map((perm) => this.moduleAccessRepo.create({ role_code: savedRole.code, module_code: perm.module_code, action_type: perm.action_type, access_flag: perm.access_flag, level_type: perm.level_type, appcode: perm.appcode, }), ); await this.moduleAccessRepo.save(clonedPermissions); } return { success: true, data: savedRole }; } async updateEntity( entityData: BaseEntity, loggedInUser: UserData, ): Promise> { if (!entityData.name) { return { success: false, error: 'Role name is required' }; } const role = entityData as Role; const resolveStatus = await this.listMasterService.getResolvedListCode( STATUS_INACTIVE, loggedInUser?.organization_id || 0, ); if (entityData.status == resolveStatus.id) { //get role by id const existingRole = await this.getEntityData( ENTITYTYPE_ROLE, entityData.id, loggedInUser, ); if (!existingRole) { return { success: false, error: 'Role not found' }; } const associatedUsers = await this.userRoleMappingRepo .createQueryBuilder("map") .innerJoin("sso_user", "usr", "map.user_id = usr.id") .where("usr.status::text = :status", { status: String(resolveStatus.id) }) .andWhere("map.role_id::text = :roleId", { roleId: String(existingRole?.id), }) .select("map") // same as SELECT map.* .getRawMany(); if (associatedUsers.length > 0) { return { success: false, error: 'Cannot deactivate role as it is associated with active users', }; } if (role.is_system === 1) { return { success: false, error: 'Cannot deactivate system role', }; } } if ( await this.roleRepository.isRoleNameExists(entityData.name, { excludeRoleId: entityData.id, organization_id: loggedInUser?.organization_id, }) ) { return { success: false, error: 'Role name already exists.', }; } const { copy_from_role_id, ...persistableData } = role; const updatedRole = await super.updateEntity(persistableData, loggedInUser); if (role.copy_from_role_id) { const sourceRole = await this.getEntityData( ENTITYTYPE_ROLE, role.copy_from_role_id, loggedInUser, ); if (!sourceRole) { return { success: false, error: 'Source role not found', }; } await this.moduleAccessRepo.delete({ role_code: role.code }); const sourcePermissions = await this.moduleAccessRepo.find({ where: { role_code: sourceRole.code }, }); const clonedPermissions = sourcePermissions.map((perm) => this.moduleAccessRepo.create({ role_code: role.code, module_code: perm.module_code, action_type: perm.action_type, access_flag: perm.access_flag, appcode: perm.appcode, level_type: perm.level_type, }), ); await this.moduleAccessRepo.save(clonedPermissions); } return { success: true, data: updatedRole }; } async getDefaultRole(data: { is_factory?: boolean; level_id?: number; level_type?: string; }): Promise { return await this.roleRepository.find(data); } }