[backend/database] Add generic versions of EnsureNoteVisibilityFor & FilterBlocked

This commit is contained in:
Laura Hausmann 2024-02-13 18:46:21 +01:00
parent 340ca21629
commit 85073fc871
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
2 changed files with 61 additions and 4 deletions

View file

@ -0,0 +1,27 @@
using System.Linq.Expressions;
namespace Iceshrimp.Backend.Core.Extensions;
public static class ExpressionExtensions {
public static Expression<Func<TFirstParam, TResult>> Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second
) {
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
private static Expression Replace(this Expression expression, Expression searchEx, Expression replaceEx) {
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression) ?? throw new NullReferenceException();
}
private class ReplaceVisitor(Expression from, Expression to) : ExpressionVisitor {
public override Expression? Visit(Expression? node) {
return node == from ? to : base.Visit(node);
}
}
}

View file

@ -1,3 +1,4 @@
using System.Linq.Expressions;
using Iceshrimp.Backend.Controllers.Attributes;
using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
@ -100,11 +101,17 @@ public static class QueryableExtensions {
}
public static IQueryable<Note> EnsureVisibleFor(this IQueryable<Note> query, User? user) {
if (user == null)
return query.Where(note => note.VisibilityIsPublicOrHome)
.Where(note => !note.LocalOnly);
return user == null
? query.Where(note => note.VisibilityIsPublicOrHome && !note.LocalOnly)
: query.Where(note => note.IsVisibleFor(user));
}
return query.Where(note => note.IsVisibleFor(user));
public static IQueryable<TSource> EnsureNoteVisibilityFor<TSource>(
this IQueryable<TSource> query, Expression<Func<TSource, Note?>> predicate, User? user
) {
return query.Where(user == null
? predicate.Compose(p => p == null || (p.VisibilityIsPublicOrHome && !p.LocalOnly))
: predicate.Compose(p => p == null || p.IsVisibleFor(user)));
}
public static IQueryable<Note> PrecomputeVisibilities(this IQueryable<Note> query, User? user) {
@ -128,6 +135,29 @@ public static class QueryableExtensions {
(!note.Reply.User.IsBlockedBy(user) && !note.Reply.User.IsBlocking(user)));
}
public static IQueryable<TSource> FilterBlocked<TSource>(
this IQueryable<TSource> query, Expression<Func<TSource, User?>> predicate, User? user
) {
return user == null ? query : query.Where(predicate.Compose(p => p == null || !p.IsBlocking(user)));
}
public static IQueryable<TSource> FilterBlocked<TSource>(
this IQueryable<TSource> query, Expression<Func<TSource, Note?>> predicate, User? user
) {
if (user == null)
return query;
return query.Where(predicate.Compose(note => note == null ||
(!note.User.IsBlocking(user) &&
!note.User.IsBlockedBy(user) &&
(note.Renote == null ||
(!note.Renote.User.IsBlockedBy(user) &&
!note.Renote.User.IsBlocking(user))) &&
(note.Reply == null ||
(!note.Reply.User.IsBlockedBy(user) &&
!note.Reply.User.IsBlocking(user))))));
}
public static IQueryable<Note> FilterMuted(this IQueryable<Note> query, User user) {
//TODO: handle muted instances