import { Inject, Injectable, UnauthorizedException } from '@nestjs/common' import * as bcrypt from 'bcrypt' import { PrismaService } from 'nestjs-prisma' import { JwtService } from '@nestjs/jwt' import { securityConfig, type SecurityConfig } from 'src/common/configs' import { CreateUserDto } from 'src/users/dto/create-user.dto' import { EmailScene } from 'src/email/dto/email.dto' import { EmailService } from 'src/email/email.service' import { ResetPassword } from './dto/reset-password.dto' import { Token, TokenPayload } from './dto/token.dto' @Injectable() export class UsersService { constructor( private jwtService: JwtService, private prismaService: PrismaService, private emailService: EmailService, @Inject(securityConfig.KEY) private secureConfig: SecurityConfig, ) {} async registerByEmail(userToCreate: CreateUserDto) { const { email, token, verifyCode, username, password } = userToCreate await this.emailService.verifyEmail({ email, token, verifyCode, scene: EmailScene.register, }) const hashedPassword = await bcrypt.hash( password, this.secureConfig.bcryptSaltOrRound, ) const user = await this.prismaService.user.create({ data: { username, email, password: hashedPassword }, }) return this.generateTokens({ userId: user.id }) } async loginByEmail(email: string, password: string) { const user = await this.prismaService.user.findUniqueOrThrow({ where: { email }, }) const passwordValid = await bcrypt.compare(password, user.password) if (!passwordValid) { throw new UnauthorizedException('Invalid password') } return this.generateTokens({ userId: user.id }) } async resetPasswordByEmail(data: ResetPassword, userId: string) { const { email, token, verifyCode, password } = data await this.emailService.verifyEmail({ email, token, verifyCode, scene: EmailScene.forgetPassword, }) const hashedPassword = await bcrypt.hash( password, this.secureConfig.bcryptSaltOrRound, ) const user = await this.prismaService.user.update({ where: { id: userId }, data: { password: hashedPassword }, }) return this.generateTokens({ userId: user.id }) } private generateTokens(payload: TokenPayload): Token { const accessToken = this.jwtService.sign(payload, { secret: this.secureConfig.jwt_access_secret, expiresIn: this.secureConfig.expiresIn, }) const refreshToken = this.jwtService.sign(payload, { secret: this.secureConfig.jwt_refresh_secret, expiresIn: this.secureConfig.refreshIn, }) return { accessToken, refreshToken, ...payload } } }