From 465c212c1f83ae35b5b6f95dda1d1ddd3c1f1457 Mon Sep 17 00:00:00 2001 From: Jeremie BRISON <ext.sopra.jbrison@grandlyon.com> Date: Wed, 16 Dec 2020 12:23:19 +0100 Subject: [PATCH] feat(changeEmail) : Add end point + services + updates user model --- src/users/change-email.dto.ts | 10 ++++++++++ src/users/user.interface.ts | 2 ++ src/users/user.schema.ts | 6 ++++++ src/users/users.controller.ts | 17 +++++++++++++++++ src/users/users.service.ts | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) create mode 100644 src/users/change-email.dto.ts diff --git a/src/users/change-email.dto.ts b/src/users/change-email.dto.ts new file mode 100644 index 000000000..eb783e449 --- /dev/null +++ b/src/users/change-email.dto.ts @@ -0,0 +1,10 @@ +import { IsEmail, IsNotEmpty } from 'class-validator'; + +export class EmailChangeDto { + @IsNotEmpty() + @IsEmail() + readonly newEmail: string; + @IsNotEmpty() + @IsEmail() + readonly oldEmail: string; +} diff --git a/src/users/user.interface.ts b/src/users/user.interface.ts index 0fe05c6f8..704569733 100644 --- a/src/users/user.interface.ts +++ b/src/users/user.interface.ts @@ -7,4 +7,6 @@ export interface IUser extends Document { emailVerified: boolean; validationToken: string; role: number; + changeEmailToken: string; + newEmail: string; } diff --git a/src/users/user.schema.ts b/src/users/user.schema.ts index abb11e91a..c41262a38 100644 --- a/src/users/user.schema.ts +++ b/src/users/user.schema.ts @@ -16,6 +16,12 @@ export class User { @Prop({ enum: [UserRole.admin, UserRole.user], default: UserRole.user }) role: number; + + @Prop({ default: null }) + changeEmailToken: string; + + @Prop({ default: null }) + newEmail: string; } export const UserSchema = SchemaFactory.createForClass(User); diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index c7120670e..b797570a3 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -2,6 +2,7 @@ import { Body, Controller, Get, Param, Post, Query, Request, UseGuards } from '@ import { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { PasswordChangeDto } from './change-password.dto'; +import { EmailChangeDto } from './change-email.dto'; import { CreateUserDto } from './create-user.dto'; import { UsersService } from './users.service'; @@ -44,4 +45,20 @@ export class UsersController { passwordChangeDto.newPassword ); } + + @UseGuards(JwtAuthGuard) + @Post('change-email') + @ApiResponse({ status: 201, description: 'Email confirmation send' }) + @ApiResponse({ status: 401, description: 'Invalid Email' }) + public async changeEmail(@Request() req, @Body() emailChangeDto: EmailChangeDto) { + return this.usersService.changeUserEmail(emailChangeDto.newEmail, emailChangeDto.oldEmail); + } + + @UseGuards(JwtAuthGuard) + @Post('verify-change-email') + @ApiResponse({ status: 201, description: 'Email changed' }) + @ApiResponse({ status: 401, description: 'Invalid Token' }) + public async verifyAndUpdateEmail(@Request() req, @Query('token') token: string) { + return this.usersService.verifyAndUpdateUserEmail(token); + } } diff --git a/src/users/users.service.ts b/src/users/users.service.ts index dbaed19c4..b0770d555 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -134,6 +134,38 @@ export class UsersService { } } + public async changeUserEmail(newEmail: string, oldEmail: string) { + const user = await this.findOne(oldEmail); + if (user) { + const config = this.mailerService.config; + const ejsPath = this.mailerService.getTemplateLocation(config.templates.changeEmail.ejs); + const jsonConfig = this.mailerService.loadJsonConfig(config.templates.changeEmail.json); + const token = crypto.randomBytes(64).toString('hex'); + const html = await ejs.renderFile(ejsPath, { + config, + token: token, + }); + this.mailerService.send(user.email, jsonConfig.subject, html); + user.changeEmailToken = token; + user.newEmail = newEmail; + user.save(); + } + throw new HttpException('Email sent if account exist', HttpStatus.OK); + } + + public async verifyAndUpdateUserEmail(token: string): Promise<any> { + const user = await this.userModel.findOne({ changeEmailToken: token }).exec(); + if (user) { + user.email = user.newEmail; + user.newEmail = null; + user.changeEmailToken = null; + user.save(); + return user; + } else { + throw new HttpException('Invalid token', HttpStatus.UNAUTHORIZED); + } + } + public async changeUserPassword(userId: string, oldPassword: string, newPassword: string): Promise<any> { const user = await this.findById(userId, true); const arePasswordEqual = await this.comparePassword(oldPassword, user.password); -- GitLab