From 877dd04b1f26ec667450b03a853aab724fb488e9 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 9 Jun 2025 01:22:00 +0800 Subject: [PATCH] :bug: Fixes for activities API --- .../Activity/ActivityController.cs | 19 ++++++++-- .../Activity/ActivityService.cs | 38 ++++++++++++++----- DysonNetwork.Sphere/Post/Post.cs | 2 +- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/DysonNetwork.Sphere/Activity/ActivityController.cs b/DysonNetwork.Sphere/Activity/ActivityController.cs index 2e74e61..9f72fe2 100644 --- a/DysonNetwork.Sphere/Activity/ActivityController.cs +++ b/DysonNetwork.Sphere/Activity/ActivityController.cs @@ -2,6 +2,7 @@ using DysonNetwork.Sphere.Account; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NodaTime; +using NodaTime.Text; namespace DysonNetwork.Sphere.Activity; @@ -23,11 +24,21 @@ public class ActivityController( /// Besides, when users are logged in, it will also mix the other kinds of data and who're plying to them. /// [HttpGet] - public async Task>> ListActivities([FromQuery] int? cursor, [FromQuery] int take = 20) + public async Task>> ListActivities([FromQuery] string? cursor, [FromQuery] int take = 20) { - var cursorTimestamp = cursor is <= 1000 - ? SystemClock.Instance.GetCurrentInstant() - : Instant.FromUnixTimeMilliseconds(cursor!.Value); + Instant? cursorTimestamp = null; + if (!string.IsNullOrEmpty(cursor)) + { + try + { + cursorTimestamp = InstantPattern.ExtendedIso.Parse(cursor).GetValueOrThrow(); + } + catch + { + return BadRequest("Invalid cursor format"); + } + } + HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); if (currentUserValue is not Account.Account currentUser) diff --git a/DysonNetwork.Sphere/Activity/ActivityService.cs b/DysonNetwork.Sphere/Activity/ActivityService.cs index b634c6b..9912f23 100644 --- a/DysonNetwork.Sphere/Activity/ActivityService.cs +++ b/DysonNetwork.Sphere/Activity/ActivityService.cs @@ -5,9 +5,9 @@ using NodaTime; namespace DysonNetwork.Sphere.Activity; -public class ActivityService(AppDatabase db, RelationshipService rels) +public class ActivityService(AppDatabase db, RelationshipService rels, PostService ps) { - public async Task> GetActivitiesForAnyone(int take, Instant cursor) + public async Task> GetActivitiesForAnyone(int take, Instant? cursor) { var activities = new List(); @@ -18,19 +18,31 @@ public class ActivityService(AppDatabase db, RelationshipService rels) .Include(e => e.Categories) .Include(e => e.Tags) .Where(e => e.RepliedPostId == null) - .Where(p => p.CreatedAt > cursor) + .Where(p => cursor == null || cursor > p.CreatedAt) + .OrderByDescending(p => p.PublishedAt) .FilterWithVisibility(null, [], isListing: true) .Take(take) .ToListAsync(); + posts = PostService.TruncatePostContent(posts); + posts = await ps.LoadPublishers(posts); + + var postsId = posts.Select(e => e.Id).ToList(); + var reactionMaps = await ps.GetPostReactionMapBatch(postsId); + foreach (var post in posts) + post.ReactionsCount = + reactionMaps.TryGetValue(post.Id, out var count) ? count : new Dictionary(); // Formatting data foreach (var post in posts) activities.Add(post.ToActivity()); + + if (activities.Count == 0) + activities.Add(Activity.Empty()); return activities; } - public async Task> GetActivities(int take, Instant cursor, Account.Account currentUser) + public async Task> GetActivities(int take, Instant? cursor, Account.Account currentUser) { var activities = new List(); var userFriends = await rels.ListAccountFriends(currentUser); @@ -41,21 +53,27 @@ public class ActivityService(AppDatabase db, RelationshipService rels) .Include(e => e.ForwardedPost) .Include(e => e.Categories) .Include(e => e.Tags) - .Where(e => e.RepliedPostId == null || e.RepliedPostId == currentUser.Id) - .Where(p => p.CreatedAt > cursor) + .Where(e => e.RepliedPostId == null) + .Where(p => cursor == null || p.CreatedAt > cursor) + .OrderByDescending(p => p.PublishedAt) .FilterWithVisibility(currentUser, userFriends, isListing: true) .Take(take) .ToListAsync(); + posts = PostService.TruncatePostContent(posts); + posts = await ps.LoadPublishers(posts); + + var postsId = posts.Select(e => e.Id).ToList(); + var reactionMaps = await ps.GetPostReactionMapBatch(postsId); + foreach (var post in posts) + post.ReactionsCount = + reactionMaps.TryGetValue(post.Id, out var count) ? count : new Dictionary(); // Formatting data foreach (var post in posts) activities.Add(post.ToActivity()); - + if (activities.Count == 0) - { - var now = SystemClock.Instance.GetCurrentInstant(); activities.Add(Activity.Empty()); - } return activities; } diff --git a/DysonNetwork.Sphere/Post/Post.cs b/DysonNetwork.Sphere/Post/Post.cs index 222b7c4..7aa4871 100644 --- a/DysonNetwork.Sphere/Post/Post.cs +++ b/DysonNetwork.Sphere/Post/Post.cs @@ -79,7 +79,7 @@ public class Post : ModelBase, IIdentifiedResource, IActivity Id = Id, Type = RepliedPostId is null ? "posts.new" : "posts.new.replies", ResourceIdentifier = ResourceIdentifier, - Data = null + Data = this }; } }