diff --git a/src/email-verification/dto/verify-email.dto.ts b/src/email-verification/dto/verify-email.dto.ts new file mode 100644 index 0000000..1edf763 --- /dev/null +++ b/src/email-verification/dto/verify-email.dto.ts @@ -0,0 +1,8 @@ +import {IsNotEmpty, IsString } from 'class-validator'; + +export class VerifyEmailDto { + @IsString() + @IsNotEmpty() + token: string; + +} \ No newline at end of file diff --git a/src/email-verification/email-verification.controller.ts b/src/email-verification/email-verification.controller.ts index 9dd8435..685b530 100644 --- a/src/email-verification/email-verification.controller.ts +++ b/src/email-verification/email-verification.controller.ts @@ -1,4 +1,5 @@ import { RequestEmailDto } from './dto/request-email.dto'; +import { VerifyEmailDto } from './dto/verify-email.dto'; import { EmailVerificationService } from './email-verification.service'; import { Body, Controller, Post } from '@nestjs/common'; @@ -11,4 +12,11 @@ export class EmailVerificationController { await this.emailVerificationService.sendEmail(dto.email); return { message: 'Verification link sent to your email' }; } + + @Post('verify-email') + async verifyEmail(@Body() dto: VerifyEmailDto) { + const email = await this.emailVerificationService.decodeVerificationToken(dto.token); + await this.emailVerificationService.verifyEmail(email); + return { message: 'The email is verified' }; + } } diff --git a/src/email-verification/email-verification.module.ts b/src/email-verification/email-verification.module.ts index 7a4381b..5a56ad6 100644 --- a/src/email-verification/email-verification.module.ts +++ b/src/email-verification/email-verification.module.ts @@ -5,10 +5,11 @@ import { EmailVerificationController } from './email-verification.controller'; import { EmailVerificationService } from './email-verification.service'; import { User } from '../user/entities/user.entity'; import { JwtService } from '@nestjs/jwt'; +import { UserService } from 'user/user.service'; @Module({ imports: [TypeOrmModule.forFeature([EmailVerification, User])], controllers: [EmailVerificationController], - providers: [EmailVerificationService, JwtService], + providers: [EmailVerificationService, JwtService, UserService], }) export class EmailVerificationModule {} diff --git a/src/email-verification/email-verification.service.ts b/src/email-verification/email-verification.service.ts index 2123d60..3207d20 100644 --- a/src/email-verification/email-verification.service.ts +++ b/src/email-verification/email-verification.service.ts @@ -1,6 +1,7 @@ +import { UserService } from './../user/user.service'; import { ConfigService } from '@nestjs/config'; import { JwtService } from '@nestjs/jwt'; -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { EmailVerification } from './entities/email-verification.entity'; @@ -17,6 +18,7 @@ export class EmailVerificationService { private readonly userRepo: Repository, private readonly jwtService: JwtService, private readonly configService: ConfigService, + private readonly userService: UserService, private readonly mailService: MailService, ) {} @@ -47,4 +49,26 @@ export class EmailVerificationService { await this.emailVerificationRepo.save({ user, token, expires_at }); } + + public async verifyEmail(email: string) { + await this.userService.confirmEmail(email); + } + + public async decodeVerificationToken(token: string) { + try { + const payload = await this.jwtService.verify(token, { + secret: this.configService.get('JWT_SECRET'), + }); + + if (typeof payload === 'object' && 'email' in payload) { + return payload.email; + } + throw new BadRequestException('Invalid token payload structure'); + } catch (error) { + if (error?.name === 'TokenExpiredError') { + throw new BadRequestException('Your email confirmation token has expired'); + } + } + throw new BadRequestException('Failed to verify email token'); + } } diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 668a7d6..81f0ff3 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -1,4 +1,24 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { User } from './entities/user.entity'; +import { Repository } from 'typeorm'; @Injectable() -export class UserService {} +export class UserService { + constructor( + @InjectRepository(User) + private readonly userRepo: Repository, + ) {} + + async confirmEmail(email: string) { + const user = await this.userRepo.findOne({ where: { email } }); + if (!user) throw new BadRequestException('User not found'); + + if (user.verified_at) { + throw new BadRequestException('Email already verified'); + } + + user.verified_at = new Date(); + await this.userRepo.save(user); + } +}