Skip to content

Commit

Permalink
fix: ensure same user cannot dislike a specific comment more than once
Browse files Browse the repository at this point in the history
  • Loading branch information
victormayowa committed Mar 2, 2025
1 parent e771d42 commit 2c05472
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 11 deletions.
9 changes: 6 additions & 3 deletions src/modules/comments/comments.controller.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { UserPayload } from './../user/interfaces/user-payload.interface';
import { User } from './../user/entities/user.entity';
import { Controller, Body, Post, Request, Get, Param, Delete } from '@nestjs/common';
import { CommentsService } from './comments.service';
import { CreateCommentDto } from './dtos/create-comment.dto';
Expand All @@ -15,7 +17,7 @@ export class CommentsController {
@ApiResponse({ status: 400, description: 'Bad Request.' })
@ApiResponse({ status: 500, description: 'Internal Server Error.' })
async addComment(@Body() createCommentDto: CreateCommentDto, @Request() req): Promise<CommentResponseDto> {
const { userId } = req.user;
const userId = req.user.id;
return await this.commentsService.addComment(createCommentDto, userId);
}

Expand All @@ -31,14 +33,15 @@ export class CommentsController {
@ApiResponse({ status: 404, description: 'Comment not found' })
@Post(':id/dislike')
async dislikeComment(@Param('id') id: string, @Request() req) {
const { userId } = req.user;
const userId = req.user.id;
// console.log('User ID:', userId); debug
return await this.commentsService.dislikeComment(id, userId);
}

@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<any> {
return await this.commentsService.deleteAComment(id, req.user.userId);
return await this.commentsService.deleteAComment(id, req.user.id);
}
}
17 changes: 14 additions & 3 deletions src/modules/comments/comments.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class CommentsService {
throw new CustomHttpException('You are not authorized to delete this comment', HttpStatus.FORBIDDEN);
}

await this.commentRepository.delete(comment);
await this.commentRepository.delete(comment.id);

return {
message: 'Comment deleted successfully!',
Expand All @@ -78,14 +78,25 @@ export class CommentsService {
async dislikeComment(commentId: string, userId: string): Promise<{ message: string; dislikeCount: number }> {
const comment = await this.commentRepository
.createQueryBuilder('comment')
.where('comment.id = :commentId', { commentId })
.where('comment.id = :id', { id: commentId })
.getOne();

if (!comment) {
throw new CustomHttpException('Comment not found', HttpStatus.NOT_FOUND);
}

comment.dislikes = Math.max(0, comment.dislikes + 1); // Ensure it doesn't go negative
if (!comment.dislikedBy) {
comment.dislikedBy = [];
}

// Check if the user has already disliked the comment
if (comment.dislikedBy.includes(userId)) {
throw new CustomHttpException('You have already disliked this comment', HttpStatus.BAD_REQUEST);
}

// Add the user to the dislikedBy array and increment dislikes
comment.dislikedBy.push(userId);
comment.dislikes = comment.dislikedBy.length;

await this.commentRepository.save(comment);

Expand Down
3 changes: 3 additions & 0 deletions src/modules/comments/entities/comments.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ export class Comment extends AbstractBaseEntity {

@Column({ type: 'int', default: 0 }) // Add dislikes column
dislikes: number;

@Column('simple-array', { nullable: true }) // Store user IDs as an array
dislikedBy: string[];
}
14 changes: 9 additions & 5 deletions src/modules/comments/tests/comments.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,24 @@ describe('CommentsService', () => {
it('should delete a comment successfully', async () => {
const commentId = 'comment-id';
const userId = 'user-id';
const mockUser = { id: 'user-id' };
const mockUser = { id: userId };
const mockComment = {
id: 'comment-id',
id: commentId,
model_id: '1',
model_type: 'post',
comment: 'A valid comment',
user: mockUser,
};

commentRepository.findOne.mockResolvedValue(mockComment);
commentRepository.delete.mockResolvedValue(mockComment);
commentRepository.delete.mockResolvedValue({ affected: 1 });

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(commentRepository.delete).toHaveBeenCalledWith(commentId);
expect(result).toEqual({
message: 'Comment deleted successfully!',
status: HttpStatus.OK,
Expand All @@ -150,7 +150,11 @@ describe('CommentsService', () => {
});

it('should increase the dislike count successfully', async () => {
const mockComment = { id: 'comment-id', dislikes: 2 };
const mockComment = {
id: 'comment-id',
dislikes: 2,
dislikedBy: ['user1', 'user2'], // Ensure this is initialized
};

// Mock `getOne()` from `createQueryBuilder`
mockQueryBuilder.getOne.mockResolvedValue(mockComment);
Expand Down
1 change: 1 addition & 0 deletions src/modules/products/tests/mocks/comment.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const mockComment: Comment = {
user: mockUser,
product: productMock,
dislikes: 0,
dislikedBy: [],
created_at: new Date(),
updated_at: new Date(),
};

0 comments on commit 2c05472

Please sign in to comment.