Handler.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. return new Response
  64. {
  65. MemberID = member.ID,
  66. MemberSID = member.SID,
  67. Name = member.Name,
  68. Thumb = member.Thumb,
  69. BannerUrl = member.BannerUrl,
  70. Summary = member.Summary,
  71. Intro = member.Intro,
  72. IsCreator = member.IsCreator,
  73. IsAdmin = member.IsAdmin,
  74. IsAuthCertified = member.IsAuthCertified,
  75. JoinedAt = member.JoinedAt,
  76. LastLoginAt = member.LastLoginAt,
  77. ChannelSID = member.ChannelSID,
  78. ChannelHandle = member.ChannelHandle,
  79. FollowerCount = member.Stats?.FollowerCount ?? 0,
  80. FollowingCount = member.Stats?.FollowingCount ?? 0,
  81. PostCount = member.Stats?.PostCount ?? 0,
  82. CommentCount = member.Stats?.CommentCount ?? 0,
  83. FeedPostCount = feedPostCount,
  84. AttendanceCount = member.Stats?.AttendanceCount ?? 0,
  85. ConsecutiveDays = consecutiveDays,
  86. Exp = member.Stats?.Exp ?? 0,
  87. LikeReceivedCount = member.Stats?.LikeReceivedCount ?? 0,
  88. TotalDonatedAmount = totalDonated,
  89. IsDonationPublic = member.IsDonationPublic,
  90. IsFollowing = isFollowing,
  91. IsSelf = isSelf
  92. };
  93. }
  94. }