feat: add email/phone change

This commit is contained in:
Sergey Krylov 2026-02-11 05:57:30 +03:00
parent 07e84f910b
commit 2ca5ddec9d
10 changed files with 176 additions and 7 deletions

View File

@ -0,0 +1,77 @@
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'
import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger'
import { CurrentUser, Protected } from '../../shared/decorators'
import { AccountClientGrpc } from './account.grpc'
import {
ConfirmEmailChangeRequestDto,
ConfirmPhoneChangeRequestDto,
InitEmailChangeRequestDto,
InitPhoneChangeRequestDto
} from './dto'
@Controller('account')
export class AccountController {
constructor(private readonly client: AccountClientGrpc) {}
@ApiOperation({
summary: 'Init email change',
description: 'Send confirmation code to change email'
})
@ApiBearerAuth()
@Protected()
@Post('email/init')
@HttpCode(HttpStatus.OK)
public initEmailChange(
@Body() dto: InitEmailChangeRequestDto,
@CurrentUser() userId: string
) {
return this.client.initEmailChange({ ...dto, userId })
}
@ApiOperation({
summary: 'Confirm email change',
description: 'Verify confirmation code to change email'
})
@Protected()
@ApiBearerAuth()
@Post('email/confirm')
@HttpCode(HttpStatus.OK)
public confirmEmailChange(
@Body() dto: ConfirmEmailChangeRequestDto,
@CurrentUser() userId: string
) {
return this.client.confirmEmailChange({ ...dto, userId })
}
@ApiOperation({
summary: 'Init phone change',
description: 'Send confirmation code to change phone'
})
@ApiBearerAuth()
@Protected()
@Post('phone/init')
@HttpCode(HttpStatus.OK)
public initPhoneChange(
@Body() dto: InitPhoneChangeRequestDto,
@CurrentUser() userId: string
) {
return this.client.initPhoneChange({ ...dto, userId })
}
@ApiOperation({
summary: 'Confirm phone change',
description: 'Verify confirmation code to change phone'
})
@Protected()
@ApiBearerAuth()
@Post('phone/confirm')
@HttpCode(HttpStatus.OK)
public confirmPhoneChange(
@Body() dto: ConfirmPhoneChangeRequestDto,
@CurrentUser() userId: string
) {
return this.client.confirmPhoneChange({ ...dto, userId })
}
}

View File

@ -2,7 +2,11 @@ import { Inject, Injectable, OnModuleInit } from '@nestjs/common'
import type { ClientGrpc } from '@nestjs/microservices'
import {
AccountServiceClient,
GetAccountRequest
ConfirmEmailChangeRequest,
ConfirmPhoneChangeRequest,
GetAccountRequest,
InitEmailChangeRequest,
InitPhoneChangeRequest,
} from '@teacinema/contracts/gen/account'
@Injectable()
@ -19,4 +23,20 @@ export class AccountClientGrpc implements OnModuleInit {
public getAccount(request: GetAccountRequest) {
return this.accountService.getAccount(request)
}
public initEmailChange(request: InitEmailChangeRequest) {
return this.accountService.initEmailChange(request)
}
public initPhoneChange(request: InitPhoneChangeRequest) {
return this.accountService.initPhoneChange(request)
}
public confirmEmailChange(request: ConfirmEmailChangeRequest) {
return this.accountService.confirmEmailChange(request)
}
public confirmPhoneChange(request: ConfirmPhoneChangeRequest) {
return this.accountService.confirmPhoneChange(request)
}
}

View File

@ -3,6 +3,7 @@ import { ConfigService } from '@nestjs/config'
import { ClientsModule, Transport } from '@nestjs/microservices'
import { PROTO_PATHS } from '@teacinema/contracts'
import { AccountController } from './account.controller'
import { AccountClientGrpc } from './account.grpc'
@Module({
@ -22,6 +23,7 @@ import { AccountClientGrpc } from './account.grpc'
}
])
],
controllers: [AccountController],
providers: [AccountClientGrpc],
exports: [AccountClientGrpc]
})

View File

@ -0,0 +1 @@
export * from './rq'

View File

@ -0,0 +1,19 @@
import { ApiProperty } from '@nestjs/swagger'
import { IsEmail, IsNotEmpty, IsNumberString, Length } from 'class-validator'
export class ConfirmEmailChangeRequestDto {
@ApiProperty({
example: 'mail@mail.ru'
})
@IsNotEmpty()
@IsEmail()
email: string
@ApiProperty({
example: '123456'
})
@Length(6, 6)
@IsNotEmpty()
@IsNumberString()
code: string
}

View File

@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger'
import {
IsNotEmpty,
IsNumberString,
IsPhoneNumber,
Length
} from 'class-validator'
export class ConfirmPhoneChangeRequestDto {
@ApiProperty({
example: '+79123456789'
})
@IsNotEmpty()
@IsPhoneNumber()
phone: string
@ApiProperty({
example: '123456'
})
@Length(6, 6)
@IsNotEmpty()
@IsNumberString()
code: string
}

View File

@ -0,0 +1,4 @@
export * from './init-email-change.request.dto'
export * from './confirm-email-change.request.dto'
export * from './init-phone-change.request.dto'
export * from './confirm-phone-change.request.dto'

View File

@ -0,0 +1,11 @@
import { ApiProperty } from '@nestjs/swagger'
import { IsEmail, IsNotEmpty } from 'class-validator'
export class InitEmailChangeRequestDto {
@ApiProperty({
example: 'mail@mail.ru'
})
@IsNotEmpty()
@IsEmail()
email: string
}

View File

@ -0,0 +1,11 @@
import { ApiProperty } from '@nestjs/swagger'
import { IsNotEmpty, IsPhoneNumber } from 'class-validator'
export class InitPhoneChangeRequestDto {
@ApiProperty({
example: '+79123456789'
})
@IsNotEmpty()
@IsPhoneNumber()
phone: string
}

View File

@ -1216,14 +1216,14 @@
"@sinonjs/commons" "^3.0.1"
"@teacinema/common@^1.0.0":
version "1.0.0"
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.0.0/common-1.0.0.tgz#3b79ae6eb46352ed1544535be094fe0ead244c36"
integrity sha512-L006mySvhRpUlRHf3ONbXA0RG42gbQ9QAnmQuZx4zejHEsWB9702xe18MSYcBilv+lmYkQpiX/g3p8P7suLfqQ==
version "1.0.1"
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.0.1/common-1.0.1.tgz#40ad9ced1522b53fa6e46d7f6797cc03193705ab"
integrity sha512-q3DURJbSk3k8MNWFIYaSM4LEcBgPbWa+HJmBz/nzYT4kuYitJVSXxpZ97kr0Ea+81AZwAU3JhQKlkK0SBWUi0A==
"@teacinema/contracts@^1.0.0":
version "1.0.6"
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.6/contracts-1.0.6.tgz#7aa97d4c3081b791908c90d2a12d771b5fb79bd5"
integrity sha512-2IU2S9hWtKeMpn4zRS9pJAaSryIODrRjS1q9QezQOXF6554vtQlMVr0fLVTGhNmXlbRfuje0f6HggApqPDFMaA==
version "1.0.7"
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.7/contracts-1.0.7.tgz#2c75a3118e4126d30f5c8193c4518bac3f1812ff"
integrity sha512-lE14PO/yBphYCu0BGFGyGAyvJ74v+ACz34MXA3fFo/PwThPVpudBReSG6oRyUACRybkN882GKXFU6LrJXvGbrQ==
dependencies:
"@nestjs/microservices" "^11.1.12"
protoc "33.4.0"