Handler.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Microsoft.EntityFrameworkCore;
  4. using SharedKernel.Results;
  5. namespace Application.Features.Api.Member.Profile;
  6. public sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Result<Response>>
  7. {
  8. private const string FeedBoardCode = "feed";
  9. public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
  10. {
  11. var member = await db.Member.AsNoTracking()
  12. .Where(m => m.SID == request.MemberSID && !m.IsWithdraw && !m.IsDenied)
  13. .Select(m => new
  14. {
  15. m.ID,
  16. m.SID,
  17. m.Name,
  18. m.Thumb,
  19. m.BannerUrl,
  20. m.Summary,
  21. m.Intro,
  22. m.IsCreator,
  23. m.IsAdmin,
  24. m.IsAuthCertified,
  25. JoinedAt = m.CreatedAt,
  26. m.LastLoginAt,
  27. ChannelSID = m.Channel != null ? m.Channel.SID : null,
  28. ChannelHandle = m.Channel != null ? m.Channel.Handle : null,
  29. IsDonationPublic = m.MemberApprove != null && m.MemberApprove.IsDonationPublic,
  30. Stats = m.MemberStats == null ? null : new
  31. {
  32. m.MemberStats.FollowerCount,
  33. m.MemberStats.FollowingCount,
  34. m.MemberStats.PostCount,
  35. m.MemberStats.CommentCount,
  36. m.MemberStats.AttendanceCount,
  37. m.MemberStats.Exp,
  38. m.MemberStats.LikeReceivedCount
  39. }
  40. })
  41. .FirstOrDefaultAsync(ct);
  42. if (member is null)
  43. {
  44. return Result.Failure<Response>(Error.NotFound("Member.ProfileNotFound", "회원을 찾을 수 없습니다."));
  45. }
  46. var feedBoardID = await db.Board.AsNoTracking().Where(b => b.Code == FeedBoardCode).Select(b => (int?)b.ID).FirstOrDefaultAsync(ct);
  47. var feedPostCount = feedBoardID is int fid
  48. ? await db.Post.AsNoTracking().LongCountAsync(p => p.BoardID == fid && p.MemberID == member.ID && !p.IsDeleted, ct)
  49. : 0;
  50. var consecutiveDays = await db.Attendance.AsNoTracking()
  51. .Where(a => a.MemberID == member.ID)
  52. .OrderByDescending(a => a.CreatedAt)
  53. .Select(a => (int?)a.ConsecutiveDays)
  54. .FirstOrDefaultAsync(ct) ?? 0;
  55. var viewerID = request.ViewerMemberID ?? 0;
  56. var isSelf = viewerID > 0 && viewerID == member.ID;
  57. var isFollowing = false;
  58. if (viewerID > 0 && !isSelf)
  59. {
  60. isFollowing = await db.MemberFollow.AsNoTracking().AnyAsync(f => f.FollowerMemberID == viewerID && f.FolloweeMemberID == member.ID, ct);
  61. }
  62. long? totalDonated = null;
  63. if (isSelf || member.IsDonationPublic)
  64. {
  65. totalDonated = await db.Donation.AsNoTracking().Where(d => d.SponsorMemberID == member.ID && !d.IsTest).SumAsync(d => (long?)d.Amount, ct) ?? 0;
  66. }
  67. return new Response
  68. {
  69. MemberID = member.ID,
  70. MemberSID = member.SID,
  71. Name = member.Name,
  72. Thumb = member.Thumb,
  73. BannerUrl = member.BannerUrl,
  74. Summary = member.Summary,
  75. Intro = member.Intro,
  76. IsCreator = member.IsCreator,
  77. IsAdmin = member.IsAdmin,
  78. IsAuthCertified = member.IsAuthCertified,
  79. JoinedAt = member.JoinedAt,
  80. LastLoginAt = member.LastLoginAt,
  81. ChannelSID = member.ChannelSID,
  82. ChannelHandle = member.ChannelHandle,
  83. FollowerCount = member.Stats?.FollowerCount ?? 0,
  84. FollowingCount = member.Stats?.FollowingCount ?? 0,
  85. PostCount = member.Stats?.PostCount ?? 0,
  86. CommentCount = member.Stats?.CommentCount ?? 0,
  87. FeedPostCount = feedPostCount,
  88. AttendanceCount = member.Stats?.AttendanceCount ?? 0,
  89. ConsecutiveDays = consecutiveDays,
  90. Exp = member.Stats?.Exp ?? 0,
  91. LikeReceivedCount = member.Stats?.LikeReceivedCount ?? 0,
  92. TotalDonatedAmount = totalDonated,
  93. IsDonationPublic = member.IsDonationPublic,
  94. IsFollowing = isFollowing,
  95. IsSelf = isSelf
  96. };
  97. }
  98. }