| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- using Application.Abstractions.Messaging;
- using Application.Abstractions.Data;
- using Domain.Entities.Forum.Logs;
- using Domain.Entities.Forum.ValueObject;
- using SharedKernel.Results;
- using Microsoft.EntityFrameworkCore;
- namespace Application.Features.Api.Forum.Post.Get;
- public sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Result<Response>>
- {
- public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
- {
- // 게시글 조회
- var item = await db.Post
- .Include(c => c.Board)
- .Include(c => c.BoardPrefix)
- .Include(c => c.Member).ThenInclude(m => m.MemberGrade)
- .Include(c => c.PostTag).ThenInclude(t => t.Tag)
- .FirstOrDefaultAsync(x => x.ID == request.ID && !x.IsDeleted, ct);
- if (item is null)
- {
- return Result.Failure<Response>(
- Error.NotFound("Post.NotFound", "게시글을 찾을 수 없습니다.")
- );
- }
- // 조회수 증가 (24시간 내 중복 방지)
- var cutoff = DateTime.UtcNow.AddHours(-24);
- bool isDuplicate;
- if (request.MemberID is int viewerID)
- {
- isDuplicate = await db.PostViewLog.AsNoTracking().AnyAsync(x => x.PostID == item.ID && x.MemberID == viewerID && x.CreatedAt > cutoff, ct);
- }
- else
- {
- isDuplicate = await db.PostViewLog.AsNoTracking().AnyAsync(x => x.PostID == item.ID && x.MemberID == null && x.IpAddress == request.IpAddress && x.CreatedAt > cutoff, ct);
- }
- if (!isDuplicate)
- {
- item.Views++;
- db.PostViewLog.Add(new PostViewLog
- {
- PostID = item.ID,
- MemberID = request.MemberID,
- IpAddress = request.IpAddress,
- });
- await db.SaveChangesAsync(ct);
- }
- // 이전/다음 게시글
- var prevID = await db.Post.AsNoTracking()
- .Where(x => x.BoardID == item.BoardID && x.ID < item.ID && !x.IsDeleted)
- .OrderByDescending(x => x.ID)
- .Select(x => (int?)x.ID)
- .FirstOrDefaultAsync(ct);
- var nextID = await db.Post.AsNoTracking()
- .Where(x => x.BoardID == item.BoardID && x.ID > item.ID && !x.IsDeleted)
- .OrderBy(x => x.ID)
- .Select(x => (int?)x.ID)
- .FirstOrDefaultAsync(ct);
- // 사용자별 상태
- bool hasLike = false, hasDislike = false, hasBookmark = false, hasReport = false;
- if (request.MemberID is int memberID)
- {
- hasLike = await db.PostReaction.AsNoTracking().AnyAsync(x => x.PostID == item.ID && x.MemberID == memberID && x.Reaction == Reaction.Like, ct);
- hasDislike = await db.PostReaction.AsNoTracking().AnyAsync(x => x.PostID == item.ID && x.MemberID == memberID && x.Reaction == Reaction.Dislike, ct);
- hasBookmark = await db.PostBookmark.AsNoTracking().AnyAsync(x => x.PostID == item.ID && x.MemberID == memberID, ct);
- hasReport = await db.PostReport.AsNoTracking().AnyAsync(x => x.PostID == item.ID && x.MemberID == memberID, ct);
- }
- // 태그 목록
- var tagList = item.PostTag.Select(t => new Response.TagDto(t.Tag.ID, t.Tag.Slug)).ToList();
- // 말머리
- Response.BoardPrefixDto? boardPrefix = item.BoardPrefix is not null
- ? new Response.BoardPrefixDto(
- item.BoardPrefix.ID,
- item.BoardPrefix.BoardID,
- item.BoardPrefix.Name,
- item.BoardPrefix.Color,
- item.BoardPrefix.Posts
- ) : null;
- // 작성자
- Response.WriterDto? writer = item.Member is not null
- ? new Response.WriterDto(
- item.Member.ID,
- item.Member.SID,
- item.Member.Name,
- item.Member.Thumb,
- item.Member.Icon,
- item.Member.MemberGrade?.Image,
- item.Member.Summary,
- item.Member.CreatedAt
- ) : null;
- return new Response(
- item.ID,
- item.BoardID,
- item.Board.Code,
- item.BoardPrefixID,
- item.MemberID,
- item.Subject,
- item.Content,
- item.SID,
- item.Email,
- item.Name,
- boardPrefix,
- writer,
- item.IsReply,
- item.IsAnonymous,
- item.IsSecret,
- item.IsNotice,
- item.IsSpeaker,
- item.Views,
- item.Likes,
- item.Dislikes,
- item.Comments,
- item.Reports,
- item.Images,
- item.Medias,
- item.Files,
- item.Tags,
- item.IpAddress,
- item.CreatedAt,
- tagList,
- prevID,
- nextID,
- hasLike,
- hasDislike,
- hasBookmark,
- hasReport
- );
- }
- }
|