import { BadRequestException, ConflictException, Injectable, NotFoundException } from '@nestjs/common'; import { Admin } from '../entities/admin.entity'; import { Role } from '../../roles/entities/role.entity'; import { EntityManager } from '@mikro-orm/postgresql'; import { UpdateAdminDto } from '../dto/update-admin.dto'; import { normalizePhone } from '../../util/phone.util'; import { CreateAdminDto } from '../dto/create-admin.dto'; import { AdminRepository } from '../repositories/admin.repository'; import { RoleRepository } from 'src/modules/roles/respository/role.repository'; import { NotificationPreference } from 'src/modules/notification/entities/notification-preference.entity'; @Injectable() export class AdminService { constructor( private readonly adminRepository: AdminRepository, private readonly roleRepository: RoleRepository, private readonly em: EntityManager, ) { } async create(dto: CreateAdminDto) { const { phone, firstName, lastName, roleId, notificationPrefrences } = dto; const normalizedPhone = normalizePhone(phone); const exist = await this.adminRepository.findOne({ phone: normalizedPhone, }); if (exist) { throw new BadRequestException('This phone number is already used'); } const role = await this.roleRepository.findOne({ id: roleId }) if (!role) { throw new BadRequestException('Role not found'); } return this.em.transactional(async em => { const admin = em.create(Admin, { phone: normalizedPhone, firstName, lastName, role }) const notificationPreference = em.create(NotificationPreference, { admin, events: notificationPrefrences, }) await this.em.persistAndFlush([admin, notificationPreference]); return admin }) } async findByPhone(phone: string): Promise { const normalizedPhone = normalizePhone(phone); return this.adminRepository.findOne({ phone: normalizedPhone }); } async findById(adminId: string): Promise { const admin = await this.adminRepository.findOne( { id: adminId }, { populate: ['role'] }, ); return admin; } async findAll(): Promise { return this.adminRepository.find({}, { populate: ['role'] }); } async update(adminId: string, dto: UpdateAdminDto): Promise { const admin = await this.adminRepository.findOne( { id: adminId }, { populate: ['role'] }, ); if (!admin) { throw new NotFoundException('Admin not found'); } const { roleId, ...rest } = dto; // Update scalar fields (firstName, lastName, phone) if (rest.firstName !== undefined) { admin.firstName = rest.firstName; } if (rest.lastName !== undefined) { admin.lastName = rest.lastName; } if (rest.notificationPrefrences) { // const nf = await this.em.findOne(NotificationPreference, { admin }) if (!nf) { throw new BadRequestException('Notification prefrences not found!') } nf.events = rest.notificationPrefrences await this.em.flush() } if (rest.phone !== undefined && rest.phone !== admin.phone) { const normalizedPhone = normalizePhone(rest.phone); const exists = await this.adminRepository.findOne({ phone: normalizedPhone }); if (exists) { throw new ConflictException('This Phone Number is already taken'); } admin.phone = normalizedPhone; } // Update role if roleId is provided if (roleId) { const role = await this.em.findOne(Role, { id: roleId, isSystem: false }); if (!role) { throw new NotFoundException('Role not found'); } admin.role = role } await this.em.persistAndFlush(admin); return admin; } async remove(adminId: string): Promise { const admin = await this.adminRepository.findOne({ id: adminId }); if (!admin) { throw new NotFoundException('Admin role not found'); } // admin.deletedAt=new Date() // TODO :L is this correct to soft delete return this.em.removeAndFlush(admin); } async findOrFail(adminId: string) { const admin = await this.findById(adminId) if (!admin) { throw new BadRequestException("Admin not found") } return admin } async findByIds(adminIds: string[]) { const admins = await this.adminRepository.find({ id: { $in: adminIds } }) if (adminIds.length !== admins.length) { throw new BadRequestException("some admins not found") } return admins } }