diff --git a/src/email/dto/email.dto.ts b/src/email/dto/email.dto.ts
index 9de4128..acde50c 100644
--- a/src/email/dto/email.dto.ts
+++ b/src/email/dto/email.dto.ts
@@ -3,7 +3,8 @@ import { IsEmail, IsNotEmpty } from 'class-validator'
export enum EmailScene {
register = 'register',
- forgetPassword = 'forgetPassword',
+ updatePassword = 'updatePassword',
+ updateEmail = 'updateEmail',
}
export class EmailSendDto {
diff --git a/src/email/email.controller.ts b/src/email/email.controller.ts
index dc5db09..eab53b5 100644
--- a/src/email/email.controller.ts
+++ b/src/email/email.controller.ts
@@ -1,22 +1,16 @@
-import { Body, Controller, Query, Post } from '@nestjs/common'
+import { Body, Controller, Post } from '@nestjs/common'
import { EmailService } from './email.service'
-import { ApiTags, ApiOperation, ApiQuery } from '@nestjs/swagger'
-import { EmailSendDto, EmailScene } from './dto/email.dto'
+import { ApiTags, ApiOperation } from '@nestjs/swagger'
+import { EmailSendDto } from './dto/email.dto'
@ApiTags('Email')
@Controller('api/email')
export class EmailController {
constructor(private readonly emailService: EmailService) {}
- // @ApiOperation({ summary: '测试邮件' })
- // @Post('test')
- // async sendEmailTo(@Body() payload: EmailDto) {
- // return this.emailService.sendEmailTo(payload.email)
- // }
-
@ApiOperation({ summary: '发送邮箱验证码' })
- @Post('verificationCode')
- async getRegisterToken(@Body() payload: EmailSendDto) {
- return this.emailService.getRegisterToken(payload.email, payload.scene)
+ @Post('verifyCode')
+ async sendEmailCode(@Body() payload: EmailSendDto) {
+ return this.emailService.sendEmailToken(payload.email, payload.scene)
}
}
diff --git a/src/email/email.service.ts b/src/email/email.service.ts
index dd15eb4..2b25a86 100644
--- a/src/email/email.service.ts
+++ b/src/email/email.service.ts
@@ -7,6 +7,11 @@ import { PrismaService } from 'nestjs-prisma'
@Injectable()
export class EmailService {
+ private subjectMap = {
+ [EmailScene.register]: '注册账号',
+ [EmailScene.updatePassword]: '修改密码',
+ [EmailScene.updateEmail]: '修改邮箱',
+ }
constructor(
private prismaService: PrismaService,
private mailerService: MailerService,
@@ -15,42 +20,46 @@ export class EmailService {
private secureConfig: SecurityConfig,
) {}
- async sendEmailTo(email: string) {
- return this.mailerService.sendMail({
- to: email, // list of receivers
- subject: 'Testing Nest Mailermodule with template ✔',
- template: 'index', // The `.pug` or `.hbs` extension is appended automatically.
- context: {
- // Data to be sent to template engine.
- code: 'cf1a3f828287',
- username: 'john doe',
- },
- })
- }
-
- async getRegisterToken(email: string, scene: EmailScene) {
- const user = await this.prismaService.user.findUnique({ where: { email } })
- if (user) {
- throw new ConflictException(`邮箱${email}已注册`)
+ async sendEmailToken(email: string, scene: EmailScene) {
+ switch (scene) {
+ case EmailScene.register:
+ const user = await this.prismaService.user.findUnique({
+ where: { email },
+ })
+ if (user) {
+ throw new ConflictException(`邮箱${email}已注册`)
+ }
+ break
+ case EmailScene.updatePassword:
+ await this.prismaService.user.findUniqueOrThrow({
+ where: { email },
+ })
+ break
+ case EmailScene.updateEmail:
+ await this.prismaService.user.findUniqueOrThrow({
+ where: { email },
+ })
+ break
}
- const verificationCode = this.generateVerificationCode()
+
+ const verifyCode = this.generateVerifyCode()
const registerToken = this.jwtService.sign(
{ email, scene },
- { secret: this.getEmailJwtSecret(verificationCode, scene) },
+ { secret: this.getEmailJwtSecret(verifyCode, scene) },
)
await this.mailerService.sendMail({
to: email,
- subject: '注册qiuxu.site',
- html: `您正在注册qiuxu.site,验证码为 ${verificationCode},30分钟内有效`,
+ subject: `【qiuxu.site】${this.subjectMap[scene]}`,
+ html: `您正在qiuxu.site${this.subjectMap[scene]},验证码为 ${verifyCode},30分钟内有效`,
})
return registerToken
}
- getEmailJwtSecret(verificationCode: string, scene: EmailScene) {
- return this.secureConfig.jwt_access_secret + verificationCode + scene
+ getEmailJwtSecret(verifyCode: string, scene: EmailScene) {
+ return this.secureConfig.jwt_access_secret + verifyCode + scene
}
- private generateVerificationCode() {
+ private generateVerifyCode() {
return Math.floor(Math.random() * 899999 + 100000).toString()
}
}
diff --git a/src/users/dto/create-user.dto.ts b/src/users/dto/create-user.dto.ts
index d9f1a7a..95147dc 100644
--- a/src/users/dto/create-user.dto.ts
+++ b/src/users/dto/create-user.dto.ts
@@ -22,7 +22,7 @@ export class CreateUserDto {
/** @description 验证码 */
@IsNotEmpty()
@Length(6, 6)
- verificationCode: string
+ verifyCode: string
/** @description 发送邮箱接口返回的Token */
@IsNotEmpty()
diff --git a/src/users/dto/update-password.dto.ts b/src/users/dto/update-password.dto.ts
new file mode 100644
index 0000000..85ae7d8
--- /dev/null
+++ b/src/users/dto/update-password.dto.ts
@@ -0,0 +1,17 @@
+import { IsEmail, IsNotEmpty, IsStrongPassword } from 'class-validator'
+
+export class UpdatePassword {
+ @IsNotEmpty()
+ @IsEmail()
+ email: string
+
+ @IsNotEmpty()
+ verifyCode: string
+
+ @IsNotEmpty()
+ token: string
+
+ @IsNotEmpty()
+ @IsStrongPassword()
+ password: string
+}
diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts
index 8c13848..9ebce58 100644
--- a/src/users/users.controller.ts
+++ b/src/users/users.controller.ts
@@ -1,4 +1,11 @@
-import { Controller, Get, Post, Body, UseInterceptors } from '@nestjs/common'
+import {
+ Controller,
+ Get,
+ Post,
+ Patch,
+ Body,
+ UseInterceptors,
+} from '@nestjs/common'
import { UsersService } from './users.service'
import { ApiTags, ApiOperation } from '@nestjs/swagger'
import { User } from 'src/common/decorators/user.decorator'
@@ -7,6 +14,7 @@ import { PasswordInterceptor } from 'src/common/interceptors/password.intercepto
import { PrismaService } from 'nestjs-prisma'
import { UserEntity } from './entities/user.entity'
import { CreateUserDto } from './dto/create-user.dto'
+import { UpdatePassword } from './dto/update-password.dto'
@ApiTags('User')
@Controller('api/users')
@@ -29,4 +37,17 @@ export class UsersController {
async register(@Body() userData: CreateUserDto) {
return this.userService.register(userData)
}
+
+ @ApiOperation({ summary: '修改密码' })
+ @UseInterceptors(PasswordInterceptor)
+ @Patch('me/password')
+ async updatePassord(@Body() payload: UpdatePassword): Promise {
+ return this.userService.updatePassword(payload)
+ }
+
+ // @ApiOperation({ summary: '修改邮箱' })
+ // @Patch('me/email')
+ // async updateEmail(@Body() payload: unknown) {
+ // return
+ // }
}
diff --git a/src/users/users.service.ts b/src/users/users.service.ts
index 1d41738..3a85ff8 100644
--- a/src/users/users.service.ts
+++ b/src/users/users.service.ts
@@ -6,9 +6,8 @@ import { securityConfig, SecurityConfig } from 'src/common/configs'
import { CreateUserDto } from 'src/users/dto/create-user.dto'
import { EmailSendDto, EmailScene } from 'src/email/dto/email.dto'
import { EmailService } from 'src/email/email.service'
-import { Prisma } from '@prisma/client'
import { TokenService } from './token.service'
-
+import { UpdatePassword } from './dto/update-password.dto'
@Injectable()
export class UsersService {
constructor(
@@ -24,27 +23,9 @@ export class UsersService {
await this.verifyEmail(
userToCreate.email,
userToCreate.token,
- userToCreate.verificationCode,
+ userToCreate.verifyCode,
EmailScene.register,
)
- return this.createUser(userToCreate)
- }
-
- private async verifyEmail(
- email: string,
- token: string,
- verificationCode: string,
- scene: EmailScene,
- ) {
- const payload = this.jwtService.verify(token, {
- secret: this.emailService.getEmailJwtSecret(verificationCode, scene),
- })
- if (payload.email !== email || payload.scene !== scene) {
- throw new ForbiddenException('请输入正确的邮箱验证码')
- }
- }
-
- private async createUser(userToCreate: Prisma.UserCreateInput) {
const hashedPassword = await bcrypt.hash(
userToCreate.password,
this.secureConfig.bcryptSaltOrRound,
@@ -58,4 +39,36 @@ export class UsersService {
})
return this.tokenService.generateTokens({ userId: user.id })
}
+
+ async updatePassword(payload: UpdatePassword) {
+ await this.verifyEmail(
+ payload.email,
+ payload.token,
+ payload.verifyCode,
+ EmailScene.updatePassword,
+ )
+ const hashedPassword = await bcrypt.hash(
+ payload.password,
+ this.secureConfig.bcryptSaltOrRound,
+ )
+ const user = await this.prismaService.user.update({
+ where: { email: payload.email },
+ data: { password: hashedPassword },
+ })
+ return user
+ }
+
+ private async verifyEmail(
+ email: string,
+ token: string,
+ verifyCode: string,
+ scene: EmailScene,
+ ) {
+ const payload = this.jwtService.verify(token, {
+ secret: this.emailService.getEmailJwtSecret(verifyCode, scene),
+ })
+ if (payload.email !== email || payload.scene !== scene) {
+ throw new ForbiddenException('请输入正确的邮箱验证码')
+ }
+ }
}