Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add the dislike functionality #1352

Merged
merged 9 commits into from
Mar 2, 2025
6,492 changes: 3,210 additions & 3,282 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"postinstall": "npm install --platform=linux --arch=x64 sharp"
},
"dependencies": {

"@google/generative-ai": "^0.22.0",
"@nestjs/axios": "^4.0.0",
"@nestjs/bull": "^11.0.2",
Expand All @@ -47,7 +46,6 @@
"@nestjs/swagger": "^11.0.5",
"@nestjs/typeorm": "^11.0.0",
"@types/nodemailer": "^6.4.17",

"@types/speakeasy": "^2.0.10",
"@vitalets/google-translate-api": "^9.2.1",
"aws-sdk": "^2.1692.0",
Expand Down
9 changes: 9 additions & 0 deletions src/modules/comments/comments.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ export class CommentsController {
return await this.commentsService.getAComment(id);
}

@ApiOperation({ summary: 'Dislike a comment' })
@ApiResponse({ status: 200, description: 'Dislike updated successfully' })
@ApiResponse({ status: 404, description: 'Comment not found' })
@Post(':id/dislike')
async dislikeComment(@Param('id') id: string, @Request() req) {
const { userId } = req.user;
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')
Expand Down
20 changes: 20 additions & 0 deletions src/modules/comments/comments.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,24 @@ export class CommentsService {
data: { comment },
};
}

async dislikeComment(commentId: string, userId: string): Promise<{ message: string; dislikeCount: number }> {
const comment = await this.commentRepository
.createQueryBuilder('comment')
.where('comment.id = :commentId', { 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

await this.commentRepository.save(comment);

return {
message: 'Dislike updated successfully',
dislikeCount: comment.dislikes,
};
}
}
9 changes: 9 additions & 0 deletions src/modules/comments/dtos/dislike-comment.dto
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsUUID } from 'class-validator';

export class DislikeCommentDto {
@ApiProperty({ description: 'Comment ID to dislike' })
@IsNotEmpty()
@IsUUID()
commentId: string;
}
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 @@ -19,4 +19,7 @@ export class Comment extends AbstractBaseEntity {

@Column({ nullable: true })
model_type: string;

@Column({ type: 'int', default: 0 }) // Add dislikes column
dislikes: number;
}
37 changes: 37 additions & 0 deletions src/modules/comments/tests/comments.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ import { User } from '../../user/entities/user.entity';
import { CustomHttpException } from '@shared/helpers/custom-http-filter';
import { HttpStatus } from '@nestjs/common';

const mockQueryBuilder = {
where: jest.fn().mockReturnThis(),
getOne: jest.fn(),
};

const mockCommentRepository = () => ({
create: jest.fn(),
save: jest.fn(),
findOne: jest.fn(),
delete: jest.fn(),
createQueryBuilder: jest.fn(() => mockQueryBuilder),
});

const mockUserRepository = () => ({
Expand Down Expand Up @@ -131,4 +137,35 @@ describe('CommentsService', () => {
});
});
});

describe('CommentsService - dislikeComment', () => {
it('should throw CustomHttpException if comment is not found', async () => {
commentRepository.findOne.mockResolvedValue(null);

await expect(service.dislikeComment('comment-id', 'user-id')).rejects.toThrow(CustomHttpException);
await expect(service.dislikeComment('comment-id', 'user-id')).rejects.toMatchObject({
message: 'Comment not found',
status: HttpStatus.NOT_FOUND,
});
});

it('should increase the dislike count successfully', async () => {
const mockComment = { id: 'comment-id', dislikes: 2 };

// Mock `getOne()` from `createQueryBuilder`
mockQueryBuilder.getOne.mockResolvedValue(mockComment);
commentRepository.createQueryBuilder.mockReturnValue(mockQueryBuilder);

commentRepository.save.mockResolvedValue({ ...mockComment, dislikes: 3 });

const result = await service.dislikeComment('comment-id', 'user-id');

expect(result).toEqual({
message: 'Dislike updated successfully',
dislikeCount: 3,
});

expect(commentRepository.save).toHaveBeenCalledWith({ ...mockComment, dislikes: 3 });
});
});
});
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 @@ -9,6 +9,7 @@ export const mockComment: Comment = {
model_type: 'Product',
user: mockUser,
product: productMock,
dislikes: 0,
created_at: new Date(),
updated_at: new Date(),
};