2023-09-27 16:34:23 +02:00

134 lines
4.6 KiB
TypeScript

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<boolean> {
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<Appointments | null> {
return this.appointmentRepository.findOneByUid(uid, query);
}
public async getAppointmentWithVotes(vote: Vote): Promise<Appointments | null> {
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>(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<Role>(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<Role>(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<Votes | null> {
const appointment = await this.getAppointmentWithVotes(vote);
if (appointment) {
const appointmentEntity = Appointment.hydrate<Appointment>(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);
}
}