diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts new file mode 100644 index 0000000..c39ee44 --- /dev/null +++ b/src/auth/auth.service.ts @@ -0,0 +1,110 @@ +import { ForbiddenException, Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { AuthLoginDto, AuthRegisterDto } from './dto'; +import * as argon from 'argon2'; +import { Prisma, User } from '@prisma/client'; +import { JwtService } from '@nestjs/jwt'; +import { ConfigService } from '@nestjs/config'; + +@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, + city: dto.city, + email: dto.email, + hash, + age: dto.age, + 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, + }; + } +} \ No newline at end of file