🐛 Fixes for activities API

This commit is contained in:
LittleSheep 2025-06-09 01:22:00 +08:00
parent f96de0d325
commit 877dd04b1f
3 changed files with 44 additions and 15 deletions

View File

@ -2,6 +2,7 @@ using DysonNetwork.Sphere.Account;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
using NodaTime.Text;
namespace DysonNetwork.Sphere.Activity; 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. /// Besides, when users are logged in, it will also mix the other kinds of data and who're plying to them.
/// </summary> /// </summary>
[HttpGet] [HttpGet]
public async Task<ActionResult<List<Activity>>> ListActivities([FromQuery] int? cursor, [FromQuery] int take = 20) public async Task<ActionResult<List<Activity>>> ListActivities([FromQuery] string? cursor, [FromQuery] int take = 20)
{ {
var cursorTimestamp = cursor is <= 1000 Instant? cursorTimestamp = null;
? SystemClock.Instance.GetCurrentInstant() if (!string.IsNullOrEmpty(cursor))
: Instant.FromUnixTimeMilliseconds(cursor!.Value); {
try
{
cursorTimestamp = InstantPattern.ExtendedIso.Parse(cursor).GetValueOrThrow();
}
catch
{
return BadRequest("Invalid cursor format");
}
}
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account.Account currentUser) if (currentUserValue is not Account.Account currentUser)

View File

@ -5,9 +5,9 @@ using NodaTime;
namespace DysonNetwork.Sphere.Activity; namespace DysonNetwork.Sphere.Activity;
public class ActivityService(AppDatabase db, RelationshipService rels) public class ActivityService(AppDatabase db, RelationshipService rels, PostService ps)
{ {
public async Task<List<Activity>> GetActivitiesForAnyone(int take, Instant cursor) public async Task<List<Activity>> GetActivitiesForAnyone(int take, Instant? cursor)
{ {
var activities = new List<Activity>(); var activities = new List<Activity>();
@ -18,19 +18,31 @@ public class ActivityService(AppDatabase db, RelationshipService rels)
.Include(e => e.Categories) .Include(e => e.Categories)
.Include(e => e.Tags) .Include(e => e.Tags)
.Where(e => e.RepliedPostId == null) .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) .FilterWithVisibility(null, [], isListing: true)
.Take(take) .Take(take)
.ToListAsync(); .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<string, int>();
// Formatting data // Formatting data
foreach (var post in posts) foreach (var post in posts)
activities.Add(post.ToActivity()); activities.Add(post.ToActivity());
if (activities.Count == 0)
activities.Add(Activity.Empty());
return activities; return activities;
} }
public async Task<List<Activity>> GetActivities(int take, Instant cursor, Account.Account currentUser) public async Task<List<Activity>> GetActivities(int take, Instant? cursor, Account.Account currentUser)
{ {
var activities = new List<Activity>(); var activities = new List<Activity>();
var userFriends = await rels.ListAccountFriends(currentUser); var userFriends = await rels.ListAccountFriends(currentUser);
@ -41,21 +53,27 @@ public class ActivityService(AppDatabase db, RelationshipService rels)
.Include(e => e.ForwardedPost) .Include(e => e.ForwardedPost)
.Include(e => e.Categories) .Include(e => e.Categories)
.Include(e => e.Tags) .Include(e => e.Tags)
.Where(e => e.RepliedPostId == null || e.RepliedPostId == currentUser.Id) .Where(e => e.RepliedPostId == null)
.Where(p => p.CreatedAt > cursor) .Where(p => cursor == null || p.CreatedAt > cursor)
.OrderByDescending(p => p.PublishedAt)
.FilterWithVisibility(currentUser, userFriends, isListing: true) .FilterWithVisibility(currentUser, userFriends, isListing: true)
.Take(take) .Take(take)
.ToListAsync(); .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<string, int>();
// Formatting data // Formatting data
foreach (var post in posts) foreach (var post in posts)
activities.Add(post.ToActivity()); activities.Add(post.ToActivity());
if (activities.Count == 0) if (activities.Count == 0)
{
var now = SystemClock.Instance.GetCurrentInstant();
activities.Add(Activity.Empty()); activities.Add(Activity.Empty());
}
return activities; return activities;
} }

View File

@ -79,7 +79,7 @@ public class Post : ModelBase, IIdentifiedResource, IActivity
Id = Id, Id = Id,
Type = RepliedPostId is null ? "posts.new" : "posts.new.replies", Type = RepliedPostId is null ? "posts.new" : "posts.new.replies",
ResourceIdentifier = ResourceIdentifier, ResourceIdentifier = ResourceIdentifier,
Data = null Data = this
}; };
} }
} }