Handler.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. using Application.Abstractions.Messaging;
  2. using Application.Abstractions.Data;
  3. using Domain.Entities.Forum.ValueObject;
  4. using SharedKernel.Results;
  5. using Microsoft.EntityFrameworkCore;
  6. namespace Application.Features.Api.Forum.PostReaction.Toggle;
  7. public sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Result>
  8. {
  9. public async Task<Result> Handle(Command request, CancellationToken ct)
  10. {
  11. var post = await db.Post.FirstOrDefaultAsync(x => x.ID == request.PostID, ct);
  12. if (post is null)
  13. {
  14. return Result.Failure(Error.NotFound("PostReaction.PostNotFound", "게시글을 찾을 수 없습니다."));
  15. }
  16. var existing = await db.PostReaction.FirstOrDefaultAsync(x => x.PostID == request.PostID && x.MemberID == request.MemberID, ct);
  17. // MemberStats 조회 (Like만 카운트)
  18. var giverStats = await db.MemberStats.FirstOrDefaultAsync(x => x.MemberID == request.MemberID, ct);
  19. Domain.Entities.Members.MemberStats? receiverStats = null;
  20. if (post.MemberID.HasValue && post.MemberID.Value != request.MemberID)
  21. {
  22. receiverStats = await db.MemberStats.FirstOrDefaultAsync(x => x.MemberID == post.MemberID.Value, ct);
  23. }
  24. if (existing is not null)
  25. {
  26. // 같은 반응이면 취소
  27. if (existing.Reaction == request.Reaction)
  28. {
  29. if (existing.Reaction == Reaction.Like)
  30. {
  31. post.Likes--;
  32. if (giverStats is not null) { giverStats.LikeGivenCount--; }
  33. if (receiverStats is not null) { receiverStats.LikeReceivedCount--; }
  34. }
  35. else
  36. {
  37. post.Dislikes--;
  38. }
  39. db.PostReaction.Remove(existing);
  40. }
  41. else
  42. {
  43. // 다른 반응이면 전환
  44. if (existing.Reaction == Reaction.Like)
  45. {
  46. post.Likes--;
  47. post.Dislikes++;
  48. // Like → Dislike: Like 카운트 감소
  49. if (giverStats is not null) { giverStats.LikeGivenCount--; }
  50. if (receiverStats is not null) { receiverStats.LikeReceivedCount--; }
  51. }
  52. else
  53. {
  54. post.Dislikes--;
  55. post.Likes++;
  56. // Dislike → Like: Like 카운트 증가
  57. if (giverStats is not null) { giverStats.LikeGivenCount++; }
  58. if (receiverStats is not null) { receiverStats.LikeReceivedCount++; }
  59. }
  60. existing.Reaction = request.Reaction;
  61. existing.UpdatedAt = DateTime.UtcNow;
  62. }
  63. }
  64. else
  65. {
  66. // 새 반응
  67. var reaction = new Domain.Entities.Forum.Posts.PostReaction
  68. {
  69. BoardID = post.BoardID,
  70. PostID = request.PostID,
  71. MemberID = request.MemberID,
  72. Reaction = request.Reaction
  73. };
  74. await db.PostReaction.AddAsync(reaction, ct);
  75. if (request.Reaction == Reaction.Like)
  76. {
  77. post.Likes++;
  78. if (giverStats is not null) { giverStats.LikeGivenCount++; }
  79. if (receiverStats is not null) { receiverStats.LikeReceivedCount++; }
  80. }
  81. else
  82. {
  83. post.Dislikes++;
  84. }
  85. }
  86. await db.SaveChangesAsync(ct);
  87. return Result.Success();
  88. }
  89. }