using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Application.Features.Api.Feed.Shared; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.Feed.GetTimeline; public sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var followingIDs = await db.MemberFollow.AsNoTracking() .Where(f => f.FollowerMemberID == request.MemberID && !f.IsMuted) .Select(f => f.FolloweeMemberID) .ToListAsync(ct); if (followingIDs.Count == 0) { return new Response { Total = 0, List = [] }; } var query = db.FeedPost.AsNoTracking().Where(p => !p.IsDeleted && followingIDs.Contains(p.MemberID)); var total = await query.LongCountAsync(ct); var skip = (request.Page - 1) * request.PerPage; var rows = await query .OrderByDescending(p => p.CreatedAt) .Skip(skip) .Take(request.PerPage) .Select(p => new { p.ID, AuthorSID = p.Member.SID, AuthorName = p.Member.Name, AuthorThumb = p.Member.Thumb, AuthorSummary = p.Member.Summary, IsCreator = p.Member.IsCreator, ChannelSID = p.Member.Channel != null ? p.Member.Channel.SID : null, p.Content, p.Thumbnail, p.Images, p.Medias, p.Likes, p.Comments, p.Bookmarks, p.Views, Tags = p.FeedPostTag.Select(pt => new { pt.FeedTag.Name, pt.FeedTag.Slug }).ToList(), p.CreatedAt }) .ToListAsync(ct); return new Response { Total = total, List = [..rows.Select(r => new FeedCardRow { PostID = r.ID, AuthorSID = r.AuthorSID, AuthorName = r.AuthorName, AuthorThumb = r.AuthorThumb, AuthorSummary = r.AuthorSummary, IsCreator = r.IsCreator, ChannelSID = r.ChannelSID, Subject = FeedContent.Excerpt(r.Content, 60), ContentExcerpt = FeedContent.Excerpt(r.Content, 200), Thumbnail = r.Thumbnail, Images = r.Images, Medias = r.Medias, Likes = r.Likes, Comments = r.Comments, Bookmarks = r.Bookmarks, Views = r.Views, Tags = [..r.Tags.Select(t => new FeedCardRow.TagRef { Name = t.Name, Slug = t.Slug })], CreatedAt = r.CreatedAt })] }; } }