import { ForbiddenException, Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { JwtService } from "@nestjs/jwt"; import { Prisma, User } from "@prisma/client"; import * as argon from "argon2"; import { PrismaService } from "../prisma/prisma.service"; import { AuthLoginDto, AuthRegisterDto } from "./dto"; @Injectable() export class AuthService { private readonly initialBalance = 1000; constructor( private prisma: PrismaService, private jwt: JwtService, private config: ConfigService, ) {} async signup(dto: AuthRegisterDto) { const hash = await argon.hash(dto.password); const promoCode = await this.getPromoCode(dto.promoCode); const userRole = await this.getUserRole("user"); const balance = this.calculateBalance(promoCode); try { const user = await this.createUser(dto, hash, userRole.id, balance); return this.signToken(user); } catch (error) { this.handleSignupError(error); } } private async getPromoCode(promoCode: string) { return this.prisma.promoCode.findFirst({ where: { name: promoCode }, }); } private async getUserRole(roleName: string) { return this.prisma.role.findFirst({ where: { name: roleName }, }); } private calculateBalance(promoCode: any) { let balance = this.initialBalance; if (promoCode && promoCode.value) { balance += promoCode.value; } return balance; } private async createUser( dto: AuthRegisterDto, hash: string, roleId: string, balance: number, ) { return this.prisma.user.create({ data: { firstName: dto.firstName, lastName: dto.lastName, pseudo: dto.pseudo, email: dto.email, hash, roleId, isActive: true, dollarAvailables: balance, }, }); } private handleSignupError(error: any) { if (error instanceof Prisma.PrismaClientKnownRequestError) { if (error.code === "P2002") { throw new ForbiddenException("Credentials taken"); } } throw error; } async signin(dto: AuthLoginDto) { const userDatas = await this.prisma.user.findUnique({ where: { email: dto.email }, include: { UserHasCrypto: { include: { Crypto: true } }, Role: true, }, }); if (!userDatas) throw new ForbiddenException("Credentials incorrect"); const pwMatches = await argon.verify(userDatas.hash, dto.password); if (!pwMatches) throw new ForbiddenException("Credentials incorrect"); return this.signToken(userDatas); } async signToken(user: any): Promise<{ access_token: string; user: User }> { const payload = { sub: user.id, email: user.email }; user.hash = null; const secret = this.config.get("JWT_SECRET"); const token = await this.jwt.signAsync(payload, { expiresIn: "30d", secret: secret, }); return { access_token: token, user, }; } }