From f2052410c7fbda65eee4cbe7c5ca49770c57d5a4 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 25 Aug 2025 17:47:30 +0800 Subject: [PATCH] :sparkles: Filtered realm posts --- .../Activity/ActivityService.cs | 56 +++++++++++-------- DysonNetwork.Sphere/Post/PostController.cs | 13 +++-- DysonNetwork.Sphere/Realm/RealmService.cs | 25 ++++++++- 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/DysonNetwork.Sphere/Activity/ActivityService.cs b/DysonNetwork.Sphere/Activity/ActivityService.cs index b8a1ff5..0aeaed9 100644 --- a/DysonNetwork.Sphere/Activity/ActivityService.cs +++ b/DysonNetwork.Sphere/Activity/ActivityService.cs @@ -1,6 +1,7 @@ using DysonNetwork.Shared.Proto; using DysonNetwork.Sphere.Discovery; using DysonNetwork.Sphere.Post; +using DysonNetwork.Sphere.Realm; using DysonNetwork.Sphere.WebReader; using Microsoft.EntityFrameworkCore; using NodaTime; @@ -11,6 +12,7 @@ public class ActivityService( AppDatabase db, Publisher.PublisherService pub, PostService ps, + RealmService rs, DiscoveryService ds, AccountService.AccountServiceClient accounts ) @@ -63,7 +65,7 @@ public class ActivityService( var posts = await GetAndProcessPosts(postsQuery); posts = RankPosts(posts, take); - + // Add posts to activities activities.AddRange(posts.Select(post => post.ToActivity())); @@ -123,28 +125,30 @@ public class ActivityService( var filteredPublishers = await GetFilteredPublishers(filter, currentUser, userFriends); var filteredPublishersId = filteredPublishers?.Select(e => e.Id).ToList(); + var userRealms = await rs.GetUserRealms(Guid.Parse(currentUser.Id)); + // Build and execute the posts query - var postsQuery = BuildPostsQuery(cursor, filteredPublishersId); - + var postsQuery = BuildPostsQuery(cursor, filteredPublishersId, userRealms); + // Apply visibility filtering and execute postsQuery = postsQuery .FilterWithVisibility( - currentUser, - userFriends, - filter is null ? userPublishers : [], + currentUser, + userFriends, + filter is null ? userPublishers : [], isListing: true) .Take(take * 5); // Get, process and rank posts var posts = await GetAndProcessPosts( - postsQuery, - currentUser, - userFriends, - userPublishers, + postsQuery, + currentUser, + userFriends, + userPublishers, trackViews: true); - + posts = RankPosts(posts, take); - + // Add posts to activities activities.AddRange(posts.Select(post => post.ToActivity())); @@ -197,7 +201,7 @@ public class ActivityService( private async Task GetRealmDiscoveryActivity(int count = 5) { var realms = await ds.GetCommunityRealmAsync(null, count, 0, true); - return realms.Count > 0 + return realms.Count > 0 ? new DiscoveryActivity(realms.Select(x => new DiscoveryItem("realm", x)).ToList()).ToActivity() : null; } @@ -206,7 +210,8 @@ public class ActivityService( { var popularPublishers = await GetPopularPublishers(count); return popularPublishers.Count > 0 - ? new DiscoveryActivity(popularPublishers.Select(x => new DiscoveryItem("publisher", x)).ToList()).ToActivity() + ? new DiscoveryActivity(popularPublishers.Select(x => new DiscoveryItem("publisher", x)).ToList()) + .ToActivity() : null; } @@ -252,11 +257,11 @@ public class ActivityService( var postsId = posts.Select(e => e.Id).ToList(); var reactionMaps = await ps.GetPostReactionMapBatch(postsId); - + foreach (var post in posts) { post.ReactionsCount = reactionMaps.GetValueOrDefault(post.Id, new Dictionary()); - + if (trackViews && currentUser != null) { await ps.IncreaseViewCount(post.Id, currentUser.Id.ToString()); @@ -266,7 +271,11 @@ public class ActivityService( return posts; } - private IQueryable BuildPostsQuery(Instant? cursor, List? filteredPublishersId = null) + private IQueryable BuildPostsQuery( + Instant? cursor, + List? filteredPublishersId = null, + List? userRealms = null + ) { var query = db.Posts .Include(e => e.RepliedPost) @@ -280,16 +289,19 @@ public class ActivityService( .AsQueryable(); if (filteredPublishersId != null && filteredPublishersId.Any()) - { query = query.Where(p => filteredPublishersId.Contains(p.PublisherId)); - } + if (userRealms == null) + query = query.Where(p => p.Realm == null || p.Realm.IsPublic); + else + query = query.Where(p => + p.Realm == null || p.Realm.IsPublic || p.RealmId == null || userRealms.Contains(p.RealmId.Value)); return query; } private async Task?> GetFilteredPublishers( - string? filter, - Account currentUser, + string? filter, + Account currentUser, List userFriends) { return filter?.ToLower() switch @@ -309,4 +321,4 @@ public class ActivityService( var postCount = posts.Count; return score + postCount; } -} +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs index 3274323..640981f 100644 --- a/DysonNetwork.Sphere/Post/PostController.cs +++ b/DysonNetwork.Sphere/Post/PostController.cs @@ -98,7 +98,9 @@ public class PostController( userFriends = friendsResponse.AccountsId.Select(Guid.Parse).ToList(); } - var userPublishers = currentUser is null ? [] : await pub.GetUserPublishers(Guid.Parse(currentUser.Id)); + var accountId = currentUser is null ? Guid.Empty : Guid.Parse(currentUser.Id); + var userPublishers = currentUser is null ? [] : await pub.GetUserPublishers(accountId); + var userRealms = currentUser is null ? [] : await rs.GetUserRealms(accountId); var publisher = pubName == null ? null : await db.Publishers.FirstOrDefaultAsync(p => p.Name == pubName); var realm = realmName == null ? null : await db.Realms.FirstOrDefaultAsync(r => r.Slug == realmName); @@ -106,6 +108,9 @@ public class PostController( var query = db.Posts .Include(e => e.Categories) .Include(e => e.Tags) + .Include(e => e.RepliedPost) + .Include(e => e.ForwardedPost) + .Include(e => e.Realm) .AsQueryable(); if (publisher != null) query = query.Where(p => p.PublisherId == publisher.Id); @@ -119,6 +124,9 @@ public class PostController( query = query.Where(p => p.Tags.Any(c => tags.Contains(c.Slug))); if (onlyMedia) query = query.Where(e => e.Attachments.Count > 0); + + if (realm == null) + query = query.Where(p => p.RealmId == null || p.Realm == null || userRealms.Contains(p.RealmId.Value) || p.Realm.IsPublic); switch (pinned) { @@ -166,9 +174,6 @@ public class PostController( : query.OrderByDescending(e => e.PublishedAt ?? e.CreatedAt); var posts = await query - .Include(e => e.RepliedPost) - .Include(e => e.ForwardedPost) - .Include(e => e.Realm) .Skip(offset) .Take(take) .ToListAsync(); diff --git a/DysonNetwork.Sphere/Realm/RealmService.cs b/DysonNetwork.Sphere/Realm/RealmService.cs index 8ae22ca..8a50d6f 100644 --- a/DysonNetwork.Sphere/Realm/RealmService.cs +++ b/DysonNetwork.Sphere/Realm/RealmService.cs @@ -1,4 +1,5 @@ using DysonNetwork.Shared; +using DysonNetwork.Shared.Cache; using DysonNetwork.Shared.Proto; using DysonNetwork.Shared.Registry; using DysonNetwork.Sphere.Localization; @@ -12,9 +13,31 @@ public class RealmService( PusherService.PusherServiceClient pusher, AccountService.AccountServiceClient accounts, IStringLocalizer localizer, - AccountClientHelper accountsHelper + AccountClientHelper accountsHelper, + ICacheService cache ) { + private const string CacheKeyPrefix = "account:realms:"; + + public async Task> GetUserRealms(Guid accountId) + { + var cacheKey = $"{CacheKeyPrefix}{accountId}"; + var (found, cachedRealms) = await cache.GetAsyncWithStatus>(cacheKey); + if (found && cachedRealms != null) + return cachedRealms; + + var realms = await db.RealmMembers + .Include(m => m.Realm) + .Where(m => m.AccountId == accountId) + .Select(m => m.Realm!.Id) + .ToListAsync(); + + // Cache the result for 5 minutes + await cache.SetAsync(cacheKey, realms, TimeSpan.FromMinutes(5)); + + return realms; + } + public async Task SendInviteNotify(RealmMember member) { var account = await accounts.GetAccountAsync(new GetAccountRequest { Id = member.AccountId.ToString() });