From e44944edbcf03b7137995837367eebb4db57ec01 Mon Sep 17 00:00:00 2001 From: sirily11 <32106111+sirily11@users.noreply.github.com> Date: Thu, 12 Oct 2023 01:51:42 +0800 Subject: [PATCH] fix: add catch prisma error decorator --- src/auth/auth.controller.ts | 19 +++++-------- src/auth/auth.service.spec.ts | 23 ++++++++++++++++ src/auth/auth.service.ts | 8 ++++++ src/decorators/catchPrismaDecorator.ts | 37 ++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 src/decorators/catchPrismaDecorator.ts diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index f67947e..51c89b7 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -67,19 +67,12 @@ export class AuthController { }) @Post('signUp') async signup(@Body() body: CreateUserDto): Promise { - try { - const user = await this.authService.signUp(body); - const loginedUser = await this.authService.accessToken(user); - return { - user, - accessToken: loginedUser, - }; - } catch (e) { - if (e.code === 'P2002') { - throw new BadRequestException('Username already exists'); - } - throw new Error('Something went wrong'); - } + const user = await this.authService.signUp(body); + const loginedUser = await this.authService.accessToken(user); + return { + user, + accessToken: loginedUser, + }; } @UseGuards(LocalAuthGuard) diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index 1f18d3c..276e677 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -55,4 +55,27 @@ describe('Given a auth service', function () { }); expect(user).toBeDefined(); }); + + it('Should be able to signUp', async () => { + const authService = new AuthService( + new JwtService(), + userService, + mockRedis as any, + prisma, + ); + const user = await authService.signUp({ + email: '', + name: '', + password: 'password', + username: 'abc', + }); + + const user2 = await authService.signUp({ + email: 'abc@abc.com', + name: 'a', + password: 'password', + username: 'abc', + }); + expect(user).toBeDefined(); + }); }); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 040af1f..de1532a 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -20,6 +20,7 @@ import { } from './dto/mfa.authenticate.dto'; import { server } from 'webauthn'; import { Environments } from '../common/environment'; +import { catchPrismaErrorDecorator } from '../decorators/catchPrismaDecorator'; @Injectable() export class AuthService { @@ -32,6 +33,7 @@ export class AuthService { // eslint-disable-next-line prettier/prettier } + @catchPrismaErrorDecorator() async validateUser(username: string, password: string) { const user = await this.userService.findOneBy(username); const isMatched = await this.userService.comparePassword( @@ -60,10 +62,12 @@ export class AuthService { }); } + @catchPrismaErrorDecorator() async signUp(user: CreateUserDto) { return this.userService.create(user); } + @catchPrismaErrorDecorator() async getMfaRegistrationCredentials( userId: string, ): Promise { @@ -94,6 +98,7 @@ export class AuthService { * @param data * @returns credential id */ + @catchPrismaErrorDecorator() async createMfaAuthentication( userId: string, data: CreateMfaAuthenticationDto, @@ -126,6 +131,7 @@ export class AuthService { * @param userId * @param data */ + @catchPrismaErrorDecorator() async getMfaAuthenticate( userId: string, ): Promise { @@ -146,6 +152,7 @@ export class AuthService { }; } + @catchPrismaErrorDecorator() async verifyMfaAuthenticate( userId: string, data: CreateMfaAuthenticateDto, @@ -174,6 +181,7 @@ export class AuthService { return registration; } + @catchPrismaErrorDecorator() getRedisKey( userId: string, type: 'registration' | 'authentication' | 'authenticated', diff --git a/src/decorators/catchPrismaDecorator.ts b/src/decorators/catchPrismaDecorator.ts new file mode 100644 index 0000000..63ce230 --- /dev/null +++ b/src/decorators/catchPrismaDecorator.ts @@ -0,0 +1,37 @@ +import { BadRequestException, NotFoundException } from '@nestjs/common'; + +export function mapPrismaErrorToHttpException(error: any) { + if (error.code === 'P2002') { + return new BadRequestException('Duplicate entry found'); + } else if (error.code === 'P2003') { + return new BadRequestException('Key constraint failed'); + } else if (error.code === 'P2025') { + return new NotFoundException('The record was not found'); + } else if (error.code === 'P2014') { + return new BadRequestException( + 'The record violates the schema on relationship', + ); + } + if (error.name === 'PrismaClientValidationError') { + return new BadRequestException('Some of the data is invalid'); + } + return error; +} + +export function catchPrismaErrorDecorator() { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor, + ) { + const originalMethod = descriptor.value; + descriptor.value = async function (...args: any[]) { + try { + return await originalMethod.apply(this, args); + } catch (error: any) { + throw mapPrismaErrorToHttpException(error); + } + }; + return descriptor; + }; +}