[backend/masto-client] Precompute reply/renote visibility in database query
This commit is contained in:
parent
c0dfce1e2c
commit
285c2ba531
4 changed files with 42 additions and 8 deletions
|
@ -35,6 +35,7 @@ public class MastodonTimelineController(DatabaseContext db, NoteRenderer noteRen
|
|||
.FilterBlocked(user)
|
||||
.FilterMuted(user)
|
||||
.Paginate(query, ControllerContext)
|
||||
.PrecomputeVisibilities(user)
|
||||
.RenderAllForMastodonAsync(noteRenderer);
|
||||
|
||||
return Ok(res);
|
||||
|
@ -53,6 +54,7 @@ public class MastodonTimelineController(DatabaseContext db, NoteRenderer noteRen
|
|||
.FilterBlocked(user)
|
||||
.FilterMuted(user)
|
||||
.Paginate(query, ControllerContext)
|
||||
.PrecomputeVisibilities(user)
|
||||
.RenderAllForMastodonAsync(noteRenderer);
|
||||
|
||||
return Ok(res);
|
||||
|
|
|
@ -236,16 +236,30 @@ public class Note : IEntity {
|
|||
[InverseProperty(nameof(UserNotePin.Note))]
|
||||
public virtual ICollection<UserNotePin> UserNotePins { get; set; } = new List<UserNotePin>();
|
||||
|
||||
[NotMapped] public bool? PrecomputedIsReplyVisible { get; private set; } = false;
|
||||
[NotMapped] public bool? PrecomputedIsRenoteVisible { get; private set; } = false;
|
||||
|
||||
[Key]
|
||||
[Column("id")]
|
||||
[StringLength(32)]
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
[Projectable]
|
||||
public bool IsVisibleFor(User user) => VisibilityIsPublicOrHome
|
||||
|| User == user
|
||||
|| VisibleUserIds.Contains(user.Id)
|
||||
|| Mentions.Any(p => p == user.Id)
|
||||
|| (Visibility == NoteVisibility.Followers &&
|
||||
(User.IsFollowedBy(user) || ReplyUserId == user.Id));
|
||||
public bool IsVisibleFor(User? user) => VisibilityIsPublicOrHome || (user != null && IsVisibleForUser(user));
|
||||
|
||||
[Projectable]
|
||||
public bool IsVisibleForUser(User user) => User == user
|
||||
|| VisibleUserIds.Contains(user.Id)
|
||||
|| Mentions.Contains(user.Id)
|
||||
|| (Visibility == NoteVisibility.Followers &&
|
||||
(User.IsFollowedBy(user) || ReplyUserId == user.Id));
|
||||
|
||||
public Note WithPrecomputedVisibilities(bool reply, bool renote) {
|
||||
if (Reply != null)
|
||||
PrecomputedIsReplyVisible = reply;
|
||||
if (Renote != null)
|
||||
PrecomputedIsRenoteVisible = renote;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -84,6 +84,12 @@ public static class NoteQueryableExtensions {
|
|||
return query.Where(note => note.IsVisibleFor(user));
|
||||
}
|
||||
|
||||
public static IQueryable<Note> PrecomputeVisibilities(this IQueryable<Note> query, User? user) {
|
||||
return query.Select(p => p.WithPrecomputedVisibilities(p.Reply != null && p.Reply.IsVisibleFor(user),
|
||||
p.Renote != null &&
|
||||
p.Renote.IsVisibleFor(user)));
|
||||
}
|
||||
|
||||
public static IQueryable<Note> FilterBlocked(this IQueryable<Note> query, User user) {
|
||||
return query.Where(note => !note.User.IsBlocking(user) && !note.User.IsBlockedBy(user))
|
||||
.Where(note => note.Renote == null ||
|
||||
|
@ -105,9 +111,21 @@ public static class NoteQueryableExtensions {
|
|||
p.UserList.HideFromHomeTl));
|
||||
}
|
||||
|
||||
public static IEnumerable<Note> EnforceRenoteReplyVisibility(this IList<Note> list) {
|
||||
foreach (var note in list) {
|
||||
if (!note.PrecomputedIsReplyVisible ?? false)
|
||||
note.Reply = null;
|
||||
if (!note.PrecomputedIsRenoteVisible ?? false)
|
||||
note.Renote = null;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<Status>> RenderAllForMastodonAsync(
|
||||
this IQueryable<Note> notes, NoteRenderer renderer) {
|
||||
var list = await notes.ToListAsync();
|
||||
var list = (await notes.ToListAsync())
|
||||
.EnforceRenoteReplyVisibility();
|
||||
return await renderer.RenderManyAsync(list);
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ builder.Services.AddViteServices(options => {
|
|||
options.Server.UseFullDevUrl = true;
|
||||
});
|
||||
//TODO: single line only if there's no \n in the log msg (otherwise stacktraces don't work)
|
||||
builder.Services.AddLogging(logging => logging.AddSimpleConsole(options => { options.SingleLine = true; }));
|
||||
builder.Services.AddLogging(logging => logging.AddSimpleConsole(options => { options.SingleLine = false; }));
|
||||
builder.Services.AddDatabaseContext(builder.Configuration); //TODO: maybe use a dbcontext factory?
|
||||
builder.Services.AddRedis(builder.Configuration);
|
||||
builder.Services.AddSlidingWindowRateLimiter();
|
||||
|
|
Loading…
Add table
Reference in a new issue