From 296a50b316d47c7a0f48358a22c3ad4b346b4c0e Mon Sep 17 00:00:00 2001 From: ludovicGendre Date: Fri, 21 Jan 2022 10:50:15 +0100 Subject: [PATCH] feat: add confirmation mail register --- .env | 3 ++ prisma/schema.prisma | 1 + src/auth/auth.controller.ts | 14 ++++++-- src/auth/auth.module.ts | 11 ++++++- src/auth/auth.service.ts | 6 ++-- src/dtos/users/user.ts | 5 +++ .../confirmation/emailConfirmation.service.ts | 33 +++++++++++++++++++ src/email/email.module.ts | 3 +- 8 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 src/email/confirmation/emailConfirmation.service.ts diff --git a/.env b/.env index 7aa2465..d5b8806 100644 --- a/.env +++ b/.env @@ -10,3 +10,6 @@ SALT="EAsCKIFVCV5CcfJc7M24Zgegy0j9zEuu" EMAIL_SERVICE="gmail" EMAIL_USER="rencontres.limals@gmail.com" EMAIL_PASSWORD="Secret00" +JWT_VERIFICATION_TOKEN_SECRET="7AnEd5epXmdaJfUrokkQ" +JWT_VERIFICATION_TOKEN_EXPIRATION_TIME=21600 +EMAIL_CONFIRMATION_URL="https://localhost:3000/confirm-email" diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4b56bfc..3547578 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -29,6 +29,7 @@ model User { email String @unique sex Int @default(0) latitude Float? + isEmailConfirmed Boolean @default(false) longitude Float? avatarId String? @db.Uuid cityId String @db.Uuid diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index dd1272a..839f95b 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -1,15 +1,17 @@ import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; -import { AccountDto, CreateUserDto, AuthTokenDto } from '../dtos'; +import { AccountDto, CreateUserDto, AuthTokenDto, UserDto } from '../dtos'; import { AuthService } from './auth.service'; import { UserService } from '../user/user.service'; +import { EmailConfirmationService } from 'src/email/confirmation/emailConfirmation.service'; @Controller('/auth') export class AuthController { public constructor( private readonly authService: AuthService, private readonly citizenService: UserService, + private readonly emailConfirmationService: EmailConfirmationService, ) {} @Post('/register') @@ -18,10 +20,16 @@ export class AuthController { //FIXME @Body() body: CreateUserDto & { password: string }, @Body('password') password: string, - ): Promise { + ): Promise { delete body.password; const { id } = await this.citizenService.create(body); - await this.authService.register(body.username, password, id); + const account = await this.authService.register( + body.username, + password, + id, + ); + await this.emailConfirmationService.sendVerificationLink(body.email); + return account; } @Post('/login') diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index bdfe9d7..67df444 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -7,6 +7,8 @@ import { JwtStrategy } from './jwt-strategy'; import { AuthService } from './auth.service'; import { PrismaService } from 'src/prisma.service'; import { UserService } from 'src/user/user.service'; +import { EmailConfirmationService } from 'src/email/confirmation/emailConfirmation.service'; +import EmailService from 'src/email/email.service'; @Module({ imports: [ @@ -18,7 +20,14 @@ import { UserService } from 'src/user/user.service'; }), }), ], - providers: [AuthService, JwtStrategy, PrismaService, UserService], + providers: [ + AuthService, + JwtStrategy, + PrismaService, + UserService, + EmailConfirmationService, + EmailService, + ], controllers: [AuthController], }) export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 1bbd2bc..3a08715 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -4,6 +4,7 @@ import type { AuthTokenDto } from '../dtos'; import { pbkdf2Sync } from 'crypto'; import { ConfigService } from 'config/config.service'; import { PrismaService } from '../prisma.service'; +import { Account } from '@prisma/client'; @Injectable() export class AuthService { @@ -17,11 +18,12 @@ export class AuthService { username: string, password: string, id: string, - ): Promise { + ): Promise { const hashedPassword = this.hashPassword(password); const account = { username, password: hashedPassword }; - await this.prisma.account.create({ data: account }); + const result = await this.prisma.account.create({ data: account }); + return result; } public async login( diff --git a/src/dtos/users/user.ts b/src/dtos/users/user.ts index b5ea710..4db57d7 100644 --- a/src/dtos/users/user.ts +++ b/src/dtos/users/user.ts @@ -1,6 +1,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { + IsBoolean, IsEmail, IsISO8601, IsNotEmpty, @@ -71,6 +72,10 @@ export class UserDto extends CreateUserDto { @ApiProperty({ type: () => FileDto }) public avatar?: RelationInput; + @ApiProperty() + @IsBoolean() + public isEmailConfirmed!: boolean; + @ApiProperty() @IsNotEmpty() @IsUUID(4) diff --git a/src/email/confirmation/emailConfirmation.service.ts b/src/email/confirmation/emailConfirmation.service.ts new file mode 100644 index 0000000..4abc08a --- /dev/null +++ b/src/email/confirmation/emailConfirmation.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import EmailService from '../email.service'; + +interface VerificationTokenPayload { + email: string; +} + +@Injectable() +export class EmailConfirmationService { + constructor( + private readonly jwtService: JwtService, + private readonly emailService: EmailService, + ) {} + + public sendVerificationLink(email: string) { + const payload: VerificationTokenPayload = { email }; + const token = this.jwtService.sign(payload, { + secret: process.env.JWT_VERIFICATION_TOKEN_SECRET, + expiresIn: `${process.env.JWT_VERIFICATION_TOKEN_EXPIRATION_TIME}s`, + }); + + const url = `${process.env.EMAIL_CONFIRMATION_URL}?token=${token}`; + + const text = `Welcome to the application. To confirm the email address, click here: ${url}`; + + return this.emailService.sendMail({ + to: email, + subject: 'Email confirmation', + text, + }); + } +} diff --git a/src/email/email.module.ts b/src/email/email.module.ts index f5f2ded..07402a6 100644 --- a/src/email/email.module.ts +++ b/src/email/email.module.ts @@ -2,10 +2,11 @@ import { Module } from '@nestjs/common'; import EmailService from './email.service'; import EmailSchedulingController from './emailSchedule.controller'; import EmailSchedulingService from './emailSchedule.service'; +import { PrismaService } from '../prisma.service'; @Module({ controllers: [EmailSchedulingController], - providers: [EmailService, EmailSchedulingService], + providers: [EmailService, EmailSchedulingService, PrismaService], exports: [EmailService], }) export class EmailModule {}