Filtered realm posts

This commit is contained in:
2025-08-25 17:47:30 +08:00
parent 83a49be725
commit f2052410c7
3 changed files with 67 additions and 27 deletions

View File

@@ -1,6 +1,7 @@
using DysonNetwork.Shared.Proto; using DysonNetwork.Shared.Proto;
using DysonNetwork.Sphere.Discovery; using DysonNetwork.Sphere.Discovery;
using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Post;
using DysonNetwork.Sphere.Realm;
using DysonNetwork.Sphere.WebReader; using DysonNetwork.Sphere.WebReader;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
@@ -11,6 +12,7 @@ public class ActivityService(
AppDatabase db, AppDatabase db,
Publisher.PublisherService pub, Publisher.PublisherService pub,
PostService ps, PostService ps,
RealmService rs,
DiscoveryService ds, DiscoveryService ds,
AccountService.AccountServiceClient accounts AccountService.AccountServiceClient accounts
) )
@@ -63,7 +65,7 @@ public class ActivityService(
var posts = await GetAndProcessPosts(postsQuery); var posts = await GetAndProcessPosts(postsQuery);
posts = RankPosts(posts, take); posts = RankPosts(posts, take);
// Add posts to activities // Add posts to activities
activities.AddRange(posts.Select(post => post.ToActivity())); activities.AddRange(posts.Select(post => post.ToActivity()));
@@ -123,28 +125,30 @@ public class ActivityService(
var filteredPublishers = await GetFilteredPublishers(filter, currentUser, userFriends); var filteredPublishers = await GetFilteredPublishers(filter, currentUser, userFriends);
var filteredPublishersId = filteredPublishers?.Select(e => e.Id).ToList(); var filteredPublishersId = filteredPublishers?.Select(e => e.Id).ToList();
var userRealms = await rs.GetUserRealms(Guid.Parse(currentUser.Id));
// Build and execute the posts query // Build and execute the posts query
var postsQuery = BuildPostsQuery(cursor, filteredPublishersId); var postsQuery = BuildPostsQuery(cursor, filteredPublishersId, userRealms);
// Apply visibility filtering and execute // Apply visibility filtering and execute
postsQuery = postsQuery postsQuery = postsQuery
.FilterWithVisibility( .FilterWithVisibility(
currentUser, currentUser,
userFriends, userFriends,
filter is null ? userPublishers : [], filter is null ? userPublishers : [],
isListing: true) isListing: true)
.Take(take * 5); .Take(take * 5);
// Get, process and rank posts // Get, process and rank posts
var posts = await GetAndProcessPosts( var posts = await GetAndProcessPosts(
postsQuery, postsQuery,
currentUser, currentUser,
userFriends, userFriends,
userPublishers, userPublishers,
trackViews: true); trackViews: true);
posts = RankPosts(posts, take); posts = RankPosts(posts, take);
// Add posts to activities // Add posts to activities
activities.AddRange(posts.Select(post => post.ToActivity())); activities.AddRange(posts.Select(post => post.ToActivity()));
@@ -197,7 +201,7 @@ public class ActivityService(
private async Task<Activity?> GetRealmDiscoveryActivity(int count = 5) private async Task<Activity?> GetRealmDiscoveryActivity(int count = 5)
{ {
var realms = await ds.GetCommunityRealmAsync(null, count, 0, true); 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() ? new DiscoveryActivity(realms.Select(x => new DiscoveryItem("realm", x)).ToList()).ToActivity()
: null; : null;
} }
@@ -206,7 +210,8 @@ public class ActivityService(
{ {
var popularPublishers = await GetPopularPublishers(count); var popularPublishers = await GetPopularPublishers(count);
return popularPublishers.Count > 0 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; : null;
} }
@@ -252,11 +257,11 @@ public class ActivityService(
var postsId = posts.Select(e => e.Id).ToList(); var postsId = posts.Select(e => e.Id).ToList();
var reactionMaps = await ps.GetPostReactionMapBatch(postsId); var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
foreach (var post in posts) foreach (var post in posts)
{ {
post.ReactionsCount = reactionMaps.GetValueOrDefault(post.Id, new Dictionary<string, int>()); post.ReactionsCount = reactionMaps.GetValueOrDefault(post.Id, new Dictionary<string, int>());
if (trackViews && currentUser != null) if (trackViews && currentUser != null)
{ {
await ps.IncreaseViewCount(post.Id, currentUser.Id.ToString()); await ps.IncreaseViewCount(post.Id, currentUser.Id.ToString());
@@ -266,7 +271,11 @@ public class ActivityService(
return posts; return posts;
} }
private IQueryable<Post.Post> BuildPostsQuery(Instant? cursor, List<Guid>? filteredPublishersId = null) private IQueryable<Post.Post> BuildPostsQuery(
Instant? cursor,
List<Guid>? filteredPublishersId = null,
List<Guid>? userRealms = null
)
{ {
var query = db.Posts var query = db.Posts
.Include(e => e.RepliedPost) .Include(e => e.RepliedPost)
@@ -280,16 +289,19 @@ public class ActivityService(
.AsQueryable(); .AsQueryable();
if (filteredPublishersId != null && filteredPublishersId.Any()) if (filteredPublishersId != null && filteredPublishersId.Any())
{
query = query.Where(p => filteredPublishersId.Contains(p.PublisherId)); 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; return query;
} }
private async Task<List<Publisher.Publisher>?> GetFilteredPublishers( private async Task<List<Publisher.Publisher>?> GetFilteredPublishers(
string? filter, string? filter,
Account currentUser, Account currentUser,
List<Guid> userFriends) List<Guid> userFriends)
{ {
return filter?.ToLower() switch return filter?.ToLower() switch
@@ -309,4 +321,4 @@ public class ActivityService(
var postCount = posts.Count; var postCount = posts.Count;
return score + postCount; return score + postCount;
} }
} }

View File

@@ -98,7 +98,9 @@ public class PostController(
userFriends = friendsResponse.AccountsId.Select(Guid.Parse).ToList(); 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 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); var realm = realmName == null ? null : await db.Realms.FirstOrDefaultAsync(r => r.Slug == realmName);
@@ -106,6 +108,9 @@ public class PostController(
var query = db.Posts var query = db.Posts
.Include(e => e.Categories) .Include(e => e.Categories)
.Include(e => e.Tags) .Include(e => e.Tags)
.Include(e => e.RepliedPost)
.Include(e => e.ForwardedPost)
.Include(e => e.Realm)
.AsQueryable(); .AsQueryable();
if (publisher != null) if (publisher != null)
query = query.Where(p => p.PublisherId == publisher.Id); 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))); query = query.Where(p => p.Tags.Any(c => tags.Contains(c.Slug)));
if (onlyMedia) if (onlyMedia)
query = query.Where(e => e.Attachments.Count > 0); 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) switch (pinned)
{ {
@@ -166,9 +174,6 @@ public class PostController(
: query.OrderByDescending(e => e.PublishedAt ?? e.CreatedAt); : query.OrderByDescending(e => e.PublishedAt ?? e.CreatedAt);
var posts = await query var posts = await query
.Include(e => e.RepliedPost)
.Include(e => e.ForwardedPost)
.Include(e => e.Realm)
.Skip(offset) .Skip(offset)
.Take(take) .Take(take)
.ToListAsync(); .ToListAsync();

View File

@@ -1,4 +1,5 @@
using DysonNetwork.Shared; using DysonNetwork.Shared;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Proto; using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Registry; using DysonNetwork.Shared.Registry;
using DysonNetwork.Sphere.Localization; using DysonNetwork.Sphere.Localization;
@@ -12,9 +13,31 @@ public class RealmService(
PusherService.PusherServiceClient pusher, PusherService.PusherServiceClient pusher,
AccountService.AccountServiceClient accounts, AccountService.AccountServiceClient accounts,
IStringLocalizer<NotificationResource> localizer, IStringLocalizer<NotificationResource> localizer,
AccountClientHelper accountsHelper AccountClientHelper accountsHelper,
ICacheService cache
) )
{ {
private const string CacheKeyPrefix = "account:realms:";
public async Task<List<Guid>> GetUserRealms(Guid accountId)
{
var cacheKey = $"{CacheKeyPrefix}{accountId}";
var (found, cachedRealms) = await cache.GetAsyncWithStatus<List<Guid>>(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) public async Task SendInviteNotify(RealmMember member)
{ {
var account = await accounts.GetAccountAsync(new GetAccountRequest { Id = member.AccountId.ToString() }); var account = await accounts.GetAccountAsync(new GetAccountRequest { Id = member.AccountId.ToString() });