improvements

This commit is contained in:
Gsk54 2022-12-21 11:14:53 +01:00
parent c11a2c5093
commit 8651345d6e
7 changed files with 106 additions and 22 deletions

View File

@ -12,15 +12,9 @@ export class DeleteAuthUseCase {
async execute(command: DeleteAuthCommand) { async execute(command: DeleteAuthCommand) {
try { try {
const usernames = await this._usernameRepository.findAll(1, 99, { await this._usernameRepository.deleteMany({
uuid: command.deleteAuthRequest.uuid, uuid: command.deleteAuthRequest.uuid,
}); });
usernames.data.map(
async (username) =>
await this._usernameRepository.delete({
username: username.username,
}),
);
return await this._authRepository.delete({ return await this._authRepository.delete({
uuid: command.deleteAuthRequest.uuid, uuid: command.deleteAuthRequest.uuid,
}); });

View File

@ -5,6 +5,7 @@ import { Auth } from '../entities/auth';
import * as bcrypt from 'bcrypt'; import * as bcrypt from 'bcrypt';
import { NotFoundException, UnauthorizedException } from '@nestjs/common'; import { NotFoundException, UnauthorizedException } from '@nestjs/common';
import { UsernameRepository } from '../../adapters/secondaries/username.repository'; import { UsernameRepository } from '../../adapters/secondaries/username.repository';
import { Username } from '../entities/username';
@QueryHandler(ValidateAuthQuery) @QueryHandler(ValidateAuthQuery)
export class ValidateAuthUseCase { export class ValidateAuthUseCase {
@ -14,19 +15,23 @@ export class ValidateAuthUseCase {
) {} ) {}
async execute(validate: ValidateAuthQuery): Promise<Auth> { async execute(validate: ValidateAuthQuery): Promise<Auth> {
let username = new Username();
try { try {
const username = await this._usernameRepository.findOne({ username = await this._usernameRepository.findOne({
username: validate.username, username: validate.username,
}); });
} catch (e) {
throw new NotFoundException();
}
try {
const auth = await this._authRepository.findOne({ const auth = await this._authRepository.findOne({
uuid: username.uuid, uuid: username.uuid,
}); });
if (auth) { if (auth) {
const isMatch = await bcrypt.compare(validate.password, auth.password); const isMatch = await bcrypt.compare(validate.password, auth.password);
if (isMatch) return auth; if (isMatch) return auth;
throw new UnauthorizedException();
} }
throw new NotFoundException(); throw new UnauthorizedException();
} catch (e) { } catch (e) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }

View File

@ -41,6 +41,7 @@ const mockUsernameRepository = {
return Promise.resolve(usernames); return Promise.resolve(usernames);
}), }),
delete: jest.fn().mockResolvedValue(undefined), delete: jest.fn().mockResolvedValue(undefined),
deleteMany: jest.fn().mockResolvedValue(undefined),
}; };
describe('DeleteAuthUseCase', () => { describe('DeleteAuthUseCase', () => {

View File

@ -8,20 +8,38 @@ import { ValidateAuthUseCase } from '../../domain/usecases/validate-auth.usecase
import { ValidateAuthQuery } from '../../queries/validate-auth.query'; import { ValidateAuthQuery } from '../../queries/validate-auth.query';
import { UsernameRepository } from '../../adapters/secondaries/username.repository'; import { UsernameRepository } from '../../adapters/secondaries/username.repository';
import { Type } from '../../domain/dtos/type.enum'; import { Type } from '../../domain/dtos/type.enum';
import { NotFoundException, UnauthorizedException } from '@nestjs/common';
import { DatabaseException } from '../../../database/src/exceptions/DatabaseException';
const mockAuthRepository = { const mockAuthRepository = {
findOne: jest.fn().mockResolvedValue({ findOne: jest
.fn()
.mockImplementationOnce(() => ({
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
password: bcrypt.hashSync('John123', 10), password: bcrypt.hashSync('John123', 10),
}), }))
.mockImplementationOnce(() => ({
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
password: bcrypt.hashSync('John123', 10),
})),
}; };
const mockUsernameRepository = { const mockUsernameRepository = {
findOne: jest.fn().mockResolvedValue({ findOne: jest
.fn()
.mockImplementationOnce(() => ({
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91', uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
username: 'john.doe@email.com', username: 'john.doe@email.com',
type: Type.EMAIL, type: Type.EMAIL,
}), }))
.mockImplementationOnce(() => {
throw new DatabaseException();
})
.mockImplementationOnce(() => ({
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
username: 'john.doe@email.com',
type: Type.EMAIL,
})),
}; };
describe('ValidateAuthUseCase', () => { describe('ValidateAuthUseCase', () => {
@ -56,7 +74,23 @@ describe('ValidateAuthUseCase', () => {
new ValidateAuthQuery('john.doe@email.com', 'John123'), new ValidateAuthQuery('john.doe@email.com', 'John123'),
); );
expect(bcrypt.compareSync('John123', auth.password)).toBeTruthy(); expect(auth.uuid).toBe('bb281075-1b98-4456-89d6-c643d3044a91');
});
it('should not validate an auth with unknown username and returns not found exception', async () => {
await expect(
validateAuthUseCase.execute(
new ValidateAuthQuery('jane.doe@email.com', 'Jane123'),
),
).rejects.toBeInstanceOf(NotFoundException);
});
it('should not validate an auth with wrong password and returns unauthorized exception', async () => {
await expect(
validateAuthUseCase.execute(
new ValidateAuthQuery('john.doe@email.com', 'John1234'),
),
).rejects.toBeInstanceOf(UnauthorizedException);
}); });
}); });
}); });

View File

@ -151,7 +151,26 @@ export abstract class PrismaRepository<T> implements IRepository<T> {
return entity; return entity;
} catch (e) { } catch (e) {
console.log(e); if (e instanceof PrismaClientKnownRequestError) {
throw new DatabaseException(
PrismaClientKnownRequestError.name,
e.code,
e.message,
);
} else {
throw new DatabaseException();
}
}
}
async deleteMany(where: any): Promise<void> {
try {
const entity = await this._prisma[this._model].deleteMany({
where: where,
});
return entity;
} catch (e) {
if (e instanceof PrismaClientKnownRequestError) { if (e instanceof PrismaClientKnownRequestError) {
throw new DatabaseException( throw new DatabaseException(
PrismaClientKnownRequestError.name, PrismaClientKnownRequestError.name,

View File

@ -13,4 +13,5 @@ export interface IRepository<T> {
update(uuid: string, entity: Partial<T>, include?: any): Promise<T>; update(uuid: string, entity: Partial<T>, include?: any): Promise<T>;
updateWhere(where: any, entity: Partial<T> | any, include?: any): Promise<T>; updateWhere(where: any, entity: Partial<T> | any, include?: any): Promise<T>;
delete(uuid: string): Promise<void>; delete(uuid: string): Promise<void>;
deleteMany(where: any): Promise<void>;
} }

View File

@ -33,7 +33,7 @@ const fakeEntityCreated: FakeEntity = {
uuid: 'some-uuid', uuid: 'some-uuid',
}; };
const fakeEntities: FakeEntity[] = []; let fakeEntities: FakeEntity[] = [];
Array.from({ length: 10 }).forEach(() => { Array.from({ length: 10 }).forEach(() => {
fakeEntities.push(createRandomEntity()); fakeEntities.push(createRandomEntity());
}); });
@ -117,6 +117,20 @@ const mockPrismaService = {
throw new Error(); throw new Error();
} }
}), }),
deleteMany: jest.fn().mockImplementation((params: any) => {
const foundEntities = fakeEntities.filter((entity) =>
entity.name.startsWith(params?.where?.name),
);
if (foundEntities.length == 0) {
throw new Error();
}
fakeEntities = fakeEntities.filter(
(entity) => !entity.name.startsWith(params?.where?.name),
);
}),
}, },
}; };
@ -241,4 +255,20 @@ describe('PrismaRepository', () => {
expect(entity.name).toBe(fakeEntities[0].name); expect(entity.name).toBe(fakeEntities[0].name);
}); });
}); });
describe('deleteMany', () => {
it('should delete many entities', async () => {
await fakeRepository.deleteMany({ name: 'name' });
const nbEntities = fakeEntities.filter((entity) =>
entity.name.startsWith('name'),
).length;
expect(nbEntities).toBe(0);
});
it("should throw an exception if an entity doesn't exist", async () => {
await expect(
fakeRepository.deleteMany({ name: 'fake-name' }),
).rejects.toBeInstanceOf(DatabaseException);
});
});
}); });