diff --git a/src/modules/password-reset/presenter/controllers/password-reset.controller.test.ts b/src/modules/password-reset/presenter/controllers/password-reset.controller.test.ts index 974e746..ad231fc 100644 --- a/src/modules/password-reset/presenter/controllers/password-reset.controller.test.ts +++ b/src/modules/password-reset/presenter/controllers/password-reset.controller.test.ts @@ -8,6 +8,7 @@ import { DeepMocked, createMock } from 'test/utils/create-mock'; import { MockPasswordReset } from 'test/factories/password-reset-mock'; import { UserNotFoundError } from '@modules/user/domain/errors/user-not-found.error'; import { InternalServerErrorException } from '@nestjs/common'; +import { PasswordResetNotFoundError } from '@modules/password-reset/domain/errors/password-reset-not-found.error'; describe('PasswordResetController', () => { let controller: PasswordResetController; @@ -53,6 +54,41 @@ describe('PasswordResetController', () => { requestPasswordResetUseCase.exec.mockResolvedValueOnce(left(new Error())); const call = async () => await controller.request(faker.internet.email()); + + expect(call).rejects.toThrow(InternalServerErrorException); + }); + }); + + describe('validateCode', () => { + it('should return that the code is valid', async () => { + validatePasswordResetUseCase.exec.mockResolvedValueOnce( + right({ + matches: true, + }), + ); + + const result = await controller.validateCode('A'.repeat(8)); + + expect(result.isValid).toBeTruthy(); + }); + + it('should return that the code is invalid if it was not found', async () => { + validatePasswordResetUseCase.exec.mockResolvedValueOnce( + left(new PasswordResetNotFoundError()), + ); + + const result = await controller.validateCode('A'.repeat(8)); + + expect(result.isValid).toBeFalsy(); + }); + + it('should throw an internal server exception when receiving an unknown error', async () => { + validatePasswordResetUseCase.exec.mockResolvedValueOnce( + left(new Error()), + ); + + const call = async () => await controller.validateCode('A'.repeat(8)); + expect(call).rejects.toThrow(InternalServerErrorException); }); }); diff --git a/src/modules/password-reset/presenter/controllers/password-reset.controller.ts b/src/modules/password-reset/presenter/controllers/password-reset.controller.ts index 5f58246..508331f 100644 --- a/src/modules/password-reset/presenter/controllers/password-reset.controller.ts +++ b/src/modules/password-reset/presenter/controllers/password-reset.controller.ts @@ -4,11 +4,14 @@ import { ValidatePasswordResetUseCase } from '@modules/password-reset/domain/use import { UserNotFoundError } from '@modules/user/domain/errors/user-not-found.error'; import { Controller, + Get, InternalServerErrorException, Param, Post, } from '@nestjs/common'; import { ApiHeader, ApiOperation, ApiTags } from '@nestjs/swagger'; +import { PasswordResetCodeValidationViewModel } from '../models/view-models/password-reset-code-validation.view-model'; +import { PasswordResetNotFoundError } from '@modules/password-reset/domain/errors/password-reset-not-found.error'; @ApiTags('Password Resets') @Controller('password-resets') @@ -37,4 +40,27 @@ export class PasswordResetController { throw new InternalServerErrorException(); } + + @ApiOperation({ summary: 'Validates a password reset code' }) + @ApiHeader({ name: 'Accept-Language', example: 'en', required: false }) + @Get('validate/:code') + public async validateCode( + @Param('code') code: string, + ): Promise { + const result = await this.validatePasswordResetUseCase.exec({ + code, + }); + + if (result.isRight()) { + return { isValid: result.value.matches }; + } + + if (result.value instanceof PasswordResetNotFoundError) { + return { + isValid: false, + }; + } + + throw new InternalServerErrorException(); + } } diff --git a/src/modules/password-reset/presenter/models/view-models/password-reset-code-validation.view-model.ts b/src/modules/password-reset/presenter/models/view-models/password-reset-code-validation.view-model.ts new file mode 100644 index 0000000..c0514ee --- /dev/null +++ b/src/modules/password-reset/presenter/models/view-models/password-reset-code-validation.view-model.ts @@ -0,0 +1,6 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class PasswordResetCodeValidationViewModel { + @ApiProperty() + isValid: boolean; +}