From 504966365a6225c5e2f5088f0f8f58e2dead3b4a Mon Sep 17 00:00:00 2001 From: Prosper Date: Sat, 1 Mar 2025 22:39:15 +0100 Subject: [PATCH] feat(comment Service): add delete comment functionality with authorization checks --- src/modules/comments/comments.controller.ts | 9 ++- src/modules/comments/comments.service.ts | 21 +++++++ .../comments/tests/comments.service.spec.ts | 55 +++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/modules/comments/comments.controller.ts b/src/modules/comments/comments.controller.ts index a0d6f48dd..c9a4b6239 100644 --- a/src/modules/comments/comments.controller.ts +++ b/src/modules/comments/comments.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Body, Post, Request, Get, Param } from '@nestjs/common'; +import { Controller, Body, Post, Request, Get, Param, Delete } from '@nestjs/common'; import { CommentsService } from './comments.service'; import { CreateCommentDto } from './dtos/create-comment.dto'; import { CommentResponseDto } from './dtos/comment-response.dto'; @@ -25,4 +25,11 @@ export class CommentsController { async getAComment(@Param('id') id: string): Promise { return await this.commentsService.getAComment(id); } + + @ApiOperation({ summary: 'Delete a comment' }) + @ApiResponse({ status: 200, description: 'The comment has been deleted successfully.' }) + @Delete(':id/delete') + async deleteAComment(@Param('id') id: string, @Request() req): Promise { + return await this.commentsService.deleteAComment(id, req.user.userId); + } } diff --git a/src/modules/comments/comments.service.ts b/src/modules/comments/comments.service.ts index 14469c782..c6cec2f78 100644 --- a/src/modules/comments/comments.service.ts +++ b/src/modules/comments/comments.service.ts @@ -53,4 +53,25 @@ export class CommentsService { data: { comment }, }; } + + async deleteAComment(commentId: string, userId: string) { + const comment = await this.commentRepository.findOne({ where: { id: commentId }, relations: ['user'] }); + if (!comment) { + throw new CustomHttpException('Comment not found', HttpStatus.NOT_FOUND); + } + + const isOwner = comment.user.id === userId; + + if (!isOwner) { + throw new CustomHttpException('You are not authorized to delete this comment', HttpStatus.FORBIDDEN); + } + + await this.commentRepository.delete(comment); + + return { + message: 'Comment deleted successfully!', + status: HttpStatus.OK, + data: { comment }, + }; + } } diff --git a/src/modules/comments/tests/comments.service.spec.ts b/src/modules/comments/tests/comments.service.spec.ts index 02a34b91b..403ce827c 100644 --- a/src/modules/comments/tests/comments.service.spec.ts +++ b/src/modules/comments/tests/comments.service.spec.ts @@ -11,6 +11,8 @@ import { HttpStatus } from '@nestjs/common'; const mockCommentRepository = () => ({ create: jest.fn(), save: jest.fn(), + findOne: jest.fn(), + delete: jest.fn(), }); const mockUserRepository = () => ({ @@ -75,5 +77,58 @@ describe('CommentsService', () => { commentedBy: 'John Doe', }); }); + + describe('deleteComment', () => { + it('should throw CustomHttpException if comment is not found', async () => { + commentRepository.findOne.mockResolvedValue(null); + + await expect(service.deleteAComment('comment-id', 'user-id')).rejects.toThrow(CustomHttpException); + await expect(service.deleteAComment('comment-id', 'user-id')).rejects.toMatchObject({ + message: 'Comment not found', + status: HttpStatus.NOT_FOUND, + }); + }); + + it('should throw CustomHttpException if user is not the owner of the comment', async () => { + const mockOwner = { id: 'owner-id' }; + const mockComment = { id: 'comment-id', user: mockOwner }; + + commentRepository.findOne.mockResolvedValue(mockComment); + + await expect(service.deleteAComment('comment-id', 'another-user-id')).rejects.toThrow(CustomHttpException); + await expect(service.deleteAComment('comment-id', 'another-user-id')).rejects.toMatchObject({ + message: 'You are not authorized to delete this comment', + status: HttpStatus.FORBIDDEN, + }); + }); + + it('should delete a comment successfully', async () => { + const commentId = 'comment-id'; + const userId = 'user-id'; + const mockUser = { id: 'user-id' }; + const mockComment = { + id: 'comment-id', + model_id: '1', + model_type: 'post', + comment: 'A valid comment', + user: mockUser, + }; + + commentRepository.findOne.mockResolvedValue(mockComment); + commentRepository.delete.mockResolvedValue(mockComment); + + console.log(await commentRepository.findOne({ where: { id: commentId }, relations: ['user'] })); // Debugging + + const result = await service.deleteAComment(commentId, userId); + + expect(commentRepository.findOne).toHaveBeenCalledWith({ where: { id: commentId }, relations: ['user'] }); + expect(commentRepository.delete).toHaveBeenCalledWith(mockComment); + expect(result).toEqual({ + message: 'Comment deleted successfully!', + status: HttpStatus.OK, + data: { comment: mockComment }, + }); + }); + }); }); });