Skip to content

Commit 665f840

Browse files
committed
fix: reset password move to auth
1 parent 96c7864 commit 665f840

File tree

5 files changed

+222
-65
lines changed

5 files changed

+222
-65
lines changed

openapi.json

Lines changed: 107 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"hash": "0eacc23250757482f417c1f6658687b8a20367a3881b8f7c1d1a0dd6a87d4a8a",
2+
"hash": "8fa4352badf47ee1a3486b4100f2e79f8f7fe294b54379d7af2067b8eef57d41",
33
"openapi": "3.0.0",
44
"paths": {
55
"/hello": {
@@ -371,6 +371,58 @@
371371
]
372372
}
373373
},
374+
"/auth/@resetPasswordByPhone": {
375+
"post": {
376+
"operationId": "resetPasswordByPhone",
377+
"summary": "",
378+
"description": "Reset password by phone",
379+
"parameters": [],
380+
"requestBody": {
381+
"required": true,
382+
"content": {
383+
"application/json": {
384+
"schema": {
385+
"$ref": "#/components/schemas/ResetPasswordByPhoneDto"
386+
}
387+
}
388+
}
389+
},
390+
"responses": {
391+
"204": {
392+
"description": ""
393+
}
394+
},
395+
"tags": [
396+
"auth"
397+
]
398+
}
399+
},
400+
"/auth/@resetPasswordByEmail": {
401+
"post": {
402+
"operationId": "resetPasswordByEmail",
403+
"summary": "",
404+
"description": "Reset password by email",
405+
"parameters": [],
406+
"requestBody": {
407+
"required": true,
408+
"content": {
409+
"application/json": {
410+
"schema": {
411+
"$ref": "#/components/schemas/ResetPasswordByEmailDto"
412+
}
413+
}
414+
}
415+
},
416+
"responses": {
417+
"204": {
418+
"description": ""
419+
}
420+
},
421+
"tags": [
422+
"auth"
423+
]
424+
}
425+
},
374426
"/users": {
375427
"post": {
376428
"operationId": "createUser",
@@ -810,41 +862,6 @@
810862
]
811863
}
812864
},
813-
"/users/{userId}/@resetPassword": {
814-
"post": {
815-
"operationId": "resetPassword",
816-
"summary": "",
817-
"description": "Reset password",
818-
"parameters": [
819-
{
820-
"name": "userId",
821-
"required": true,
822-
"in": "path",
823-
"schema": {
824-
"type": "string"
825-
}
826-
}
827-
],
828-
"requestBody": {
829-
"required": true,
830-
"content": {
831-
"application/json": {
832-
"schema": {
833-
"$ref": "#/components/schemas/ResetPasswordDto"
834-
}
835-
}
836-
}
837-
},
838-
"responses": {
839-
"204": {
840-
"description": ""
841-
}
842-
},
843-
"tags": [
844-
"user"
845-
]
846-
}
847-
},
848865
"/users/{userId}/@updatePassword": {
849866
"post": {
850867
"operationId": "updatePassword",
@@ -3522,6 +3539,60 @@
35223539
"refreshToken"
35233540
]
35243541
},
3542+
"ResetPasswordByPhoneDto": {
3543+
"type": "object",
3544+
"properties": {
3545+
"phone": {
3546+
"type": "string",
3547+
"description": "手机号"
3548+
},
3549+
"key": {
3550+
"type": "string",
3551+
"description": "验证码 key"
3552+
},
3553+
"code": {
3554+
"type": "string",
3555+
"description": "验证码 code"
3556+
},
3557+
"password": {
3558+
"type": "string",
3559+
"description": "密码"
3560+
}
3561+
},
3562+
"required": [
3563+
"phone",
3564+
"key",
3565+
"code",
3566+
"password"
3567+
]
3568+
},
3569+
"ResetPasswordByEmailDto": {
3570+
"type": "object",
3571+
"properties": {
3572+
"email": {
3573+
"type": "string",
3574+
"description": "手机号"
3575+
},
3576+
"key": {
3577+
"type": "string",
3578+
"description": "验证码 key"
3579+
},
3580+
"code": {
3581+
"type": "string",
3582+
"description": "验证码 code"
3583+
},
3584+
"password": {
3585+
"type": "string",
3586+
"description": "密码"
3587+
}
3588+
},
3589+
"required": [
3590+
"email",
3591+
"key",
3592+
"code",
3593+
"password"
3594+
]
3595+
},
35253596
"CreateUserDto": {
35263597
"type": "object",
35273598
"properties": {
@@ -3761,15 +3832,6 @@
37613832
}
37623833
}
37633834
},
3764-
"ResetPasswordDto": {
3765-
"type": "object",
3766-
"properties": {
3767-
"password": {
3768-
"type": "string",
3769-
"description": "密码"
3770-
}
3771-
}
3772-
},
37733835
"UpdatePasswordDto": {
37743836
"type": "object",
37753837
"properties": {

src/auth/auth.controller.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { GithubDto } from './dto/github.dto';
2626
import { LoginByEmailDto, LoginByPhoneDto, LoginDto, LogoutDto } from './dto/login.dto';
2727
import { RefreshTokenDto } from './dto/refresh-token.dto';
2828
import { RegisterByEmailDto, RegisterbyPhoneDto, RegisterDto } from './dto/register.dto';
29+
import { ResetPasswordByEmailDto, ResetPasswordByPhoneDto } from './dto/reset-password.dto';
2930
import { SignTokenDto } from './dto/sign-token.dto';
3031
import { SessionWithToken, Token } from './entities/session-with-token.entity';
3132

@@ -424,4 +425,54 @@ export class AuthController {
424425
tokenExpireAt,
425426
};
426427
}
428+
429+
/**
430+
* Reset password by phone
431+
*/
432+
@ApiOperation({ operationId: 'resetPasswordByPhone' })
433+
@HttpCode(HttpStatus.NO_CONTENT)
434+
@Post('@resetPasswordByPhone')
435+
async resetPasswordByPhone(@Body() dto: ResetPasswordByPhoneDto): Promise<void> {
436+
const user = await this.userService.findByPhone(dto.phone);
437+
if (!user) {
438+
throw new NotFoundException({
439+
code: ErrorCodes.USER_NOT_FOUND,
440+
message: `User with phone ${dto.phone} not found.`,
441+
});
442+
}
443+
444+
if (!(await this.captchaService.consume(dto.key, dto.code))) {
445+
throw new BadRequestException({
446+
code: ErrorCodes.CAPTCHA_INVALID,
447+
message: 'captcha invalid.',
448+
});
449+
}
450+
451+
await this.userService.updatePassword(user.id, dto.password);
452+
}
453+
454+
/**
455+
* Reset password by email
456+
*/
457+
@ApiOperation({ operationId: 'resetPasswordByEmail' })
458+
@HttpCode(HttpStatus.NO_CONTENT)
459+
@Post('@resetPasswordByEmail')
460+
async resetPasswordByEmail(@Body() dto: ResetPasswordByEmailDto): Promise<void> {
461+
const user = await this.userService.findByEmail(dto.email);
462+
if (!user) {
463+
throw new NotFoundException({
464+
code: ErrorCodes.USER_NOT_FOUND,
465+
message: `User with email ${dto.email} not found.`,
466+
});
467+
}
468+
469+
if (!(await this.captchaService.consume(dto.key, dto.code))) {
470+
throw new BadRequestException({
471+
code: ErrorCodes.CAPTCHA_INVALID,
472+
message: 'captcha invalid.',
473+
});
474+
}
475+
476+
await this.userService.updatePassword(user.id, dto.password);
477+
}
427478
}

src/auth/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const ErrorCodes = {
33
USER_ALREADY_EXISTS: 'USER_ALREADY_EXISTS',
44
CAPTCHA_INVALID: 'CAPTCHA_INVALID',
55
TOO_MANY_LOGIN_ATTEMPTS: 'TOO_MANY_LOGIN_ATTEMPTS',
6+
USER_NOT_FOUND: 'USER_NOT_FOUND',
67
};
78

89
export const GithubAccessTokenUrl = 'https://github.com/login/oauth/access_token';

src/auth/dto/reset-password.dto.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { IsEmail, IsMobilePhone, IsNotEmpty, IsString } from 'class-validator';
2+
3+
import { IsPassword } from 'src/common/validate';
4+
5+
export class ResetPasswordByPhoneDto {
6+
/**
7+
* 手机号
8+
*/
9+
@IsNotEmpty()
10+
@IsMobilePhone('zh-CN') // 中国大陆地区手机号
11+
phone: string;
12+
13+
/**
14+
* 验证码 key
15+
*/
16+
@IsNotEmpty()
17+
@IsString()
18+
key: string;
19+
20+
/**
21+
* 验证码 code
22+
*/
23+
@IsNotEmpty()
24+
@IsString()
25+
code: string;
26+
27+
/**
28+
* 密码
29+
*/
30+
@IsNotEmpty()
31+
@IsPassword()
32+
password: string;
33+
}
34+
35+
export class ResetPasswordByEmailDto {
36+
/**
37+
* 手机号
38+
*/
39+
@IsNotEmpty()
40+
@IsEmail()
41+
email: string;
42+
43+
/**
44+
* 验证码 key
45+
*/
46+
@IsNotEmpty()
47+
@IsString()
48+
key: string;
49+
50+
/**
51+
* 验证码 code
52+
*/
53+
@IsNotEmpty()
54+
@IsString()
55+
code: string;
56+
57+
/**
58+
* 密码
59+
*/
60+
@IsNotEmpty()
61+
@IsPassword()
62+
password: string;
63+
}

src/user/user.controller.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import { NamespaceService, ErrorCodes as NsErrCodes } from 'src/namespace';
2929
import { ErrorCodes } from './constants';
3030
import { CreateUserDto } from './dto/create-user.dto';
3131
import { ListUsersQuery } from './dto/list-users.dto';
32-
import { ResetPasswordDto } from './dto/reset-password.dto';
3332
import { UpdatePasswordDto } from './dto/update-password.dto';
3433
import { UpdateUserDto } from './dto/update-user.dto';
3534
import { User, UserDocument } from './entities/user.entity';
@@ -420,25 +419,6 @@ export class UserController {
420419
return user.save();
421420
}
422421

423-
/**
424-
* Reset password
425-
*/
426-
@ApiOperation({ operationId: 'resetPassword' })
427-
@HttpCode(HttpStatus.NO_CONTENT)
428-
@Post(':userId/@resetPassword')
429-
async resetPassword(
430-
@Param('userId') userId: string,
431-
@Body() dto: ResetPasswordDto
432-
): Promise<void> {
433-
const user = await this.userService.updatePassword(userId, dto.password);
434-
if (!user) {
435-
throw new NotFoundException({
436-
code: ErrorCodes.USER_NOT_FOUND,
437-
message: `User ${userId} not found.`,
438-
});
439-
}
440-
}
441-
442422
/**
443423
* Update password
444424
*/

0 commit comments

Comments
 (0)