diff --git a/src/modules/squeeze/squeeze.controller.ts b/src/modules/squeeze/squeeze.controller.ts index 7a8d8cc32..6748f2a63 100644 --- a/src/modules/squeeze/squeeze.controller.ts +++ b/src/modules/squeeze/squeeze.controller.ts @@ -4,6 +4,15 @@ import { SqueezeService } from './squeeze.service'; import { SqueezeRequestDto } from './dto/squeeze.dto'; import { skipAuth } from '@shared/helpers/skipAuth'; import { UpdateSqueezeDto } from './dto/update-squeeze.dto'; +import { UseGuards } from '@nestjs/common'; +import { ApiBearerAuth } from '@nestjs/swagger'; +import { ApiOkResponse } from '@nestjs/swagger'; +import { ApiUnauthorizedResponse } from '@nestjs/swagger'; +import { ApiForbiddenResponse } from '@nestjs/swagger'; +import { ApiInternalServerErrorResponse } from '@nestjs/swagger'; +import { Delete } from '@nestjs/common'; +import { Param } from '@nestjs/common'; +import { ParseUUIDPipe } from '@nestjs/common'; @ApiTags('Squeeze') @Controller('squeeze') @@ -48,4 +57,36 @@ export class SqueezeController { }, }; } + + @Delete(':squeezeId') + @ApiBearerAuth() + @ApiOperation({ summary: 'Delete Squeeze Record' }) + @ApiOkResponse({ + description: 'Squeeze Records Deleted Successfully', + type: 'object', + example: { + message: 'Success', + status: 200, + }, + }) + @ApiUnauthorizedResponse({ + description: 'User is Unauthorized', + type: 'object', + example: { + message: 'User is currently unauthorized, kindly authenticate to continue', + status: 401, + }, + }) + @ApiForbiddenResponse({ + description: 'User is forbidden', + example: { + message: "You don't have the permission to perform this action", + status: 403, + }, + }) + @ApiInternalServerErrorResponse({ description: 'Internal Server Error' }) + async deleteSqueeze(@Param('squeezeId', ParseUUIDPipe) squeezeId: string, @Request() req) { + const authenticatedSqueezeId = req['squeeze'].id; + return this.SqueezeService.deleteSqueeze(squeezeId, authenticatedSqueezeId); + } } diff --git a/src/modules/squeeze/squeeze.service.ts b/src/modules/squeeze/squeeze.service.ts index 30fc9a95b..90920d14d 100644 --- a/src/modules/squeeze/squeeze.service.ts +++ b/src/modules/squeeze/squeeze.service.ts @@ -15,19 +15,20 @@ import { CreateSqueezeMapper } from './mapper/create-squeeze.mapper'; import { SqueezeMapper } from './mapper/squeeze.mapper'; import { UpdateSqueezeDto } from './dto/update-squeeze.dto'; import CustomExceptionHandler from '@shared/helpers/exceptionHandler'; +import { CustomHttpException } from '@shared/helpers/custom-http-filter'; @Injectable() export class SqueezeService { constructor( @InjectRepository(Squeeze) - private readonly SqueezeRepository: Repository + private readonly squeezeRepository: Repository ) {} async create(createSqueezeDto: SqueezeRequestDto) { try { const mapNewSqueeze = CreateSqueezeMapper.mapToEntity(createSqueezeDto); - const existingSqueeze = await this.SqueezeRepository.findOne({ + const existingSqueeze = await this.squeezeRepository.findOne({ where: { email: mapNewSqueeze.email, }, @@ -40,10 +41,10 @@ export class SqueezeService { }); } - const newSqueeze = this.SqueezeRepository.create({ + const newSqueeze = this.squeezeRepository.create({ ...mapNewSqueeze, }); - await this.SqueezeRepository.save(newSqueeze); + await this.squeezeRepository.save(newSqueeze); const mappedResponse = SqueezeMapper.mapToResponseFormat(newSqueeze); return { status: 'success', @@ -62,7 +63,7 @@ export class SqueezeService { async updateSqueeze(updateDto: UpdateSqueezeDto) { try { - const squeeze = await this.SqueezeRepository.findOneBy({ email: updateDto.email }); + const squeeze = await this.squeezeRepository.findOneBy({ email: updateDto.email }); if (!squeeze) { throw new NotFoundException({ @@ -79,7 +80,7 @@ export class SqueezeService { } Object.assign(squeeze, updateDto); - const updatedSqueeze = await this.SqueezeRepository.save(squeeze); + const updatedSqueeze = await this.squeezeRepository.save(squeeze); return updatedSqueeze; } catch (err) { if (this.isInstanceOfAny(err, [ForbiddenException, NotFoundException])) { @@ -96,4 +97,25 @@ export class SqueezeService { isInstanceOfAny(err: any, classes: Array<{ new (...args: any[]): any }>): boolean { return classes.some(errClass => err instanceof errClass); } + + async deleteSqueeze(squeezeId: string, authenticatedSqueezeId: string): Promise { + const squeeze = await this.squeezeRepository.findOne({ + where: { id: squeezeId }, + }); + + if (!squeeze) { + throw new CustomHttpException('Squeeze not found', HttpStatus.NOT_FOUND); + } + + if (squeeze.id !== authenticatedSqueezeId) { + throw new CustomHttpException('You are not authorized to delete this squeeze', HttpStatus.UNAUTHORIZED); + } + + await this.squeezeRepository.softDelete(squeezeId); + + return { + status: 'success', + message: 'Deletion in progress', + }; + } } diff --git a/src/modules/squeeze/tests/squeeze.service.spec.ts b/src/modules/squeeze/tests/squeeze.service.spec.ts index 5beddb644..0041fa7ee 100644 --- a/src/modules/squeeze/tests/squeeze.service.spec.ts +++ b/src/modules/squeeze/tests/squeeze.service.spec.ts @@ -12,6 +12,14 @@ describe('SqueezeService', () => { let service: SqueezeService; let repository: Repository; + const mockSqueezeRepository = { + save: jest.fn(), + findOne: jest.fn(), + findAndCount: jest.fn(), + count: jest.fn(), + softDelete: jest.fn(), + }; + beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ @@ -19,6 +27,7 @@ describe('SqueezeService', () => { { provide: getRepositoryToken(Squeeze), useClass: Repository, + useValue: mockSqueezeRepository, }, ], }).compile(); @@ -27,6 +36,10 @@ describe('SqueezeService', () => { repository = module.get>(getRepositoryToken(Squeeze)); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should be defined', () => { expect(service).toBeDefined(); }); @@ -51,31 +64,21 @@ describe('SqueezeService', () => { created_at: new Date(), updated_at: new Date(), }; - const savedEntity = { - id: '1', - ...createSqueezeDto, - created_at: new Date(), - updated_at: new Date(), + ...mappedEntity, }; - const mappedResponse = { - id: '1', - ...createSqueezeDto, - created_at: new Date(), - updated_at: new Date(), + ...mappedEntity, }; jest.spyOn(CreateSqueezeMapper, 'mapToEntity').mockReturnValue(mappedEntity); jest.spyOn(repository, 'findOne').mockReturnValue(null); - jest.spyOn(repository, 'create').mockReturnValue(savedEntity as Squeeze); jest.spyOn(repository, 'save').mockResolvedValue(savedEntity as Squeeze); jest.spyOn(SqueezeMapper, 'mapToResponseFormat').mockReturnValue(mappedResponse); const result = await service.create(createSqueezeDto); expect(CreateSqueezeMapper.mapToEntity).toHaveBeenCalledWith(createSqueezeDto); - expect(repository.create).toHaveBeenCalledWith(mappedEntity); expect(repository.save).toHaveBeenCalledWith(savedEntity); expect(SqueezeMapper.mapToResponseFormat).toHaveBeenCalledWith(savedEntity); expect(result).toEqual({ @@ -103,8 +106,43 @@ describe('SqueezeService', () => { }); await expect(service.create(createSqueezeDto)).rejects.toThrow(HttpException); + }); + }); - expect(CreateSqueezeMapper.mapToEntity).toHaveBeenCalledWith(createSqueezeDto); + describe('deleteSqueeze', () => { + it('should delete a squeeze', async () => { + const squeezeId = '1'; + const authenticatedSqueezeId = '1'; + const squeezeToDelete = { id: squeezeId, email: 'user@example.com' }; + + mockSqueezeRepository.findOne.mockResolvedValueOnce(squeezeToDelete); + mockSqueezeRepository.softDelete.mockResolvedValueOnce({ affected: 1 }); + + const result = await service.deleteSqueeze(squeezeId, authenticatedSqueezeId); + + expect(result.status).toBe('success'); + expect(result.message).toBe('Deletion in progress'); + expect(mockSqueezeRepository.findOne).toHaveBeenCalledWith({ where: { id: squeezeId } }); + expect(mockSqueezeRepository.softDelete).toHaveBeenCalledWith(squeezeId); + }); + + it('should throw an error if squeeze is not found', async () => { + const squeezeId = '1'; + const authenticatedSqueezeId = '1'; + + mockSqueezeRepository.findOne.mockResolvedValueOnce(null); + + await expect(service.deleteSqueeze(squeezeId, authenticatedSqueezeId)).rejects.toThrow(HttpException); + }); + + it('should throw an error if the user is not authorized to delete the squeeze', async () => { + const squeezeId = '1'; + const authenticatedSqueezeId = '2'; + const squeezeToDelete = { id: squeezeId, email: 'user@example.com' }; + + mockSqueezeRepository.findOne.mockResolvedValueOnce(squeezeToDelete); + + await expect(service.deleteSqueeze(squeezeId, authenticatedSqueezeId)).rejects.toThrow(HttpException); }); }); });