import BaseService from "@Services/BaseService"; import { Service } from "typedi"; import User, { Appointment, Role, Vote } from "le-coffre-resources/dist/SuperAdmin"; import VotesRepository from "@Repositories/VotesRepository"; import { Appointments, EAppointmentStatus, EVote, Prisma, Votes } from "@prisma/client"; import UsersService from "../UsersService/UsersService"; import RolesService from "../RolesService/RolesService"; import AppointmentsRepository from "@Repositories/AppointmentsRepository"; @Service() export default class LiveVoteService extends BaseService { constructor( private voteRepository: VotesRepository, private appointmentRepository: AppointmentsRepository, private userService: UsersService, private roleService: RolesService, ) { super(); } public async verifyVoterChoice(vote: Vote): Promise { const userWithRole = await this.userService.getByUidWithRole(vote.appointment.targeted_user.uid!); if (userWithRole!.role.name === "super-admin" && vote.appointment.choice === EVote.DISMISS) { return true; } if (userWithRole!.role.name !== "super-admin" && vote.appointment.choice === EVote.NOMINATE) { return true; } return false; } public getVotes(query: Prisma.VotesFindManyArgs) { return this.voteRepository.findMany(query); } /** * @description : Get a vote by uid * @throws {Error} If vote cannot be get by uid */ public getVoteByUid(uid: string, query?: Prisma.VotesInclude) { return this.voteRepository.findOneByUid(uid, query); } /** * @description : delete a vote by uid * @throws {Error} If vote cannot be get by uid */ public deleteVote(uid: string) { return this.voteRepository.delete(uid); } /** * @description : delete an appointment by uid * @throws {Error} If appointment cannot be get by uid */ public deleteAppointment(uid: string) { return this.appointmentRepository.delete(uid); } /** * @description : Get a appointment by uid * @throws {Error} If appointment cannot be get by uid */ public getAppointmentByUid(uid: string, query?: Prisma.AppointmentsInclude): Promise { return this.appointmentRepository.findOneByUid(uid, query); } public async getAppointmentWithVotes(vote: Vote): Promise { if (vote.appointment.uid) { return this.appointmentRepository.findOneByUid(vote.appointment.uid); } const appointmentByUser = await this.appointmentRepository.findMany({ where: { AND: [ { user_uid: vote.appointment.targeted_user.uid }, { status: EAppointmentStatus.OPEN }, { choice: EVote[vote.appointment.choice as keyof typeof EVote] }, ], }, include: { votes: true }, }); if (appointmentByUser.length >= 1) { return this.appointmentRepository.findOneByUidWithVotes(appointmentByUser[0]!.uid); } return null; } private async closeVote(appointment: Appointments, vote: Votes) { await this.appointmentRepository.update(vote.appointment_uid, EAppointmentStatus.CLOSED); const user = await this.userService.getByUid(appointment.user_uid, { role: true }); const userEntity = User.hydrate(user!, { strategy: "excludeAll" }); return await this.updateRole(appointment, userEntity, vote); } private async updateRole(appointment: Appointments, userEntity: User, vote: Votes) { if (appointment.choice === EVote.DISMISS) { const roles = await this.roleService.get({ where: { name: "default" } }); const roleEntity = Role.hydrate(roles[0]!, { strategy: "excludeAll" }); userEntity.role = roleEntity; await this.userService.update(appointment!.user_uid, userEntity); return vote; } else if (appointment.choice === EVote.NOMINATE) { const roles = await this.roleService.get({ where: { name: "super-admin" } }); const roleEntity = Role.hydrate(roles[0]!, { strategy: "excludeAll" }); userEntity!.role = roleEntity; await this.userService.update(appointment!.user_uid, userEntity); return vote; } return vote; } /** * @description : Create a vote * @throws {Error} If vote couldn't be created */ public async create(vote: Vote): Promise { const appointment = await this.getAppointmentWithVotes(vote); if (appointment) { const appointmentEntity = Appointment.hydrate(appointment, { strategy: "excludeAll" }); if (appointmentEntity?.votes && appointmentEntity.votes.length >= 2) { const voteCreated = await this.voteRepository.create(vote); return this.closeVote(appointment, voteCreated); } } const approvedChoice = await this.verifyVoterChoice(vote); if (!approvedChoice) return null; return this.voteRepository.create(vote); } }