[backend/masto-client] Implement visibility/blocking/muting/list filters for timelines
This commit is contained in:
parent
4aca474398
commit
4dd1997f45
7 changed files with 148 additions and 54 deletions
|
@ -28,6 +28,10 @@ public class MastodonTimelineController(DatabaseContext db, NoteRenderer noteRen
|
|||
var res = await db.Notes
|
||||
.IncludeCommonProperties()
|
||||
.FilterByFollowingAndOwn(user)
|
||||
.EnsureVisibleFor(user)
|
||||
.FilterHiddenListMembers(user)
|
||||
.FilterBlocked(user)
|
||||
.FilterMuted(user)
|
||||
.Paginate(query, 20, 40)
|
||||
.RenderAllForMastodonAsync(noteRenderer);
|
||||
|
||||
|
@ -39,9 +43,13 @@ public class MastodonTimelineController(DatabaseContext db, NoteRenderer noteRen
|
|||
[Produces("application/json")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Status>))]
|
||||
public async Task<IActionResult> GetPublicTimeline(PaginationQuery query) {
|
||||
var user = HttpContext.GetOauthUser() ?? throw new GracefulException("Failed to get user from HttpContext");
|
||||
|
||||
var res = await db.Notes
|
||||
.IncludeCommonProperties()
|
||||
.HasVisibility(Note.NoteVisibility.Public)
|
||||
.FilterBlocked(user)
|
||||
.FilterMuted(user)
|
||||
.Paginate(query, 20, 40)
|
||||
.RenderAllForMastodonAsync(noteRenderer);
|
||||
|
||||
|
|
|
@ -107,9 +107,7 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
|
|||
|
||||
public static void Configure(DbContextOptionsBuilder optionsBuilder, NpgsqlDataSource dataSource) {
|
||||
optionsBuilder.UseNpgsql(dataSource);
|
||||
optionsBuilder.UseProjectables(options => {
|
||||
options.CompatibilityMode(CompatibilityMode.Limited);
|
||||
});
|
||||
optionsBuilder.UseProjectables(options => { options.CompatibilityMode(CompatibilityMode.Full); });
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
|
@ -222,9 +220,9 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
|
|||
entity.Property(e => e.BlockerId).HasComment("The blocker user ID.");
|
||||
entity.Property(e => e.CreatedAt).HasComment("The created date of the Blocking.");
|
||||
|
||||
entity.HasOne(d => d.Blockee).WithMany(p => p.BlockingBlockees);
|
||||
entity.HasOne(d => d.Blockee).WithMany(p => p.IncomingBlocks);
|
||||
|
||||
entity.HasOne(d => d.Blocker).WithMany(p => p.BlockingBlockers);
|
||||
entity.HasOne(d => d.Blocker).WithMany(p => p.OutgoingBlocks);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Channel>(entity => {
|
||||
|
@ -513,9 +511,9 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
|
|||
entity.Property(e => e.MuteeId).HasComment("The mutee user ID.");
|
||||
entity.Property(e => e.MuterId).HasComment("The muter user ID.");
|
||||
|
||||
entity.HasOne(d => d.Mutee).WithMany(p => p.MutingMutees);
|
||||
entity.HasOne(d => d.Mutee).WithMany(p => p.IncomingMutes);
|
||||
|
||||
entity.HasOne(d => d.Muter).WithMany(p => p.MutingMuters);
|
||||
entity.HasOne(d => d.Muter).WithMany(p => p.OutgoingMutes);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Note>(entity => {
|
||||
|
|
|
@ -36,10 +36,10 @@ public class Blocking {
|
|||
public string BlockerId { get; set; } = null!;
|
||||
|
||||
[ForeignKey("BlockeeId")]
|
||||
[InverseProperty(nameof(User.BlockingBlockees))]
|
||||
[InverseProperty(nameof(User.IncomingBlocks))]
|
||||
public virtual User Blockee { get; set; } = null!;
|
||||
|
||||
[ForeignKey("BlockerId")]
|
||||
[InverseProperty(nameof(User.BlockingBlockers))]
|
||||
[InverseProperty(nameof(User.OutgoingBlocks))]
|
||||
public virtual User Blocker { get; set; } = null!;
|
||||
}
|
|
@ -39,10 +39,10 @@ public class Muting {
|
|||
[Column("expiresAt")] public DateTime? ExpiresAt { get; set; }
|
||||
|
||||
[ForeignKey("MuteeId")]
|
||||
[InverseProperty(nameof(User.MutingMutees))]
|
||||
[InverseProperty(nameof(User.IncomingMutes))]
|
||||
public virtual User Mutee { get; set; } = null!;
|
||||
|
||||
[ForeignKey("MuterId")]
|
||||
[InverseProperty(nameof(User.MutingMuters))]
|
||||
[InverseProperty(nameof(User.OutgoingMutes))]
|
||||
public virtual User Muter { get; set; } = null!;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NpgsqlTypes;
|
||||
|
||||
|
@ -73,6 +75,11 @@ public class Note {
|
|||
|
||||
[Column("visibility")] public NoteVisibility Visibility { get; set; }
|
||||
|
||||
[Projectable]
|
||||
[SuppressMessage("ReSharper", "MergeIntoLogicalPattern",
|
||||
Justification = "Projectable expression cannot contain patterns")]
|
||||
public bool VisibilityIsPublicOrHome => Visibility == NoteVisibility.Public || Visibility == NoteVisibility.Home;
|
||||
|
||||
[Column("localOnly")] public bool LocalOnly { get; set; }
|
||||
|
||||
[Column("renoteCount")] public short RenoteCount { get; set; }
|
||||
|
@ -179,15 +186,18 @@ public class Note {
|
|||
[InverseProperty(nameof(ChannelNotePin.Note))]
|
||||
public virtual ICollection<ChannelNotePin> ChannelNotePins { get; set; } = new List<ChannelNotePin>();
|
||||
|
||||
[InverseProperty(nameof(ClipNote.Note))] public virtual ICollection<ClipNote> ClipNotes { get; set; } = new List<ClipNote>();
|
||||
[InverseProperty(nameof(ClipNote.Note))]
|
||||
public virtual ICollection<ClipNote> ClipNotes { get; set; } = new List<ClipNote>();
|
||||
|
||||
[InverseProperty(nameof(Tables.HtmlNoteCacheEntry.Note))] public virtual HtmlNoteCacheEntry? HtmlNoteCacheEntry { get; set; }
|
||||
[InverseProperty(nameof(Tables.HtmlNoteCacheEntry.Note))]
|
||||
public virtual HtmlNoteCacheEntry? HtmlNoteCacheEntry { get; set; }
|
||||
|
||||
[InverseProperty(nameof(Renote))] public virtual ICollection<Note> InverseRenote { get; set; } = new List<Note>();
|
||||
|
||||
[InverseProperty(nameof(Reply))] public virtual ICollection<Note> InverseReply { get; set; } = new List<Note>();
|
||||
|
||||
[InverseProperty(nameof(NoteEdit.Note))] public virtual ICollection<NoteEdit> NoteEdits { get; set; } = new List<NoteEdit>();
|
||||
[InverseProperty(nameof(NoteEdit.Note))]
|
||||
public virtual ICollection<NoteEdit> NoteEdits { get; set; } = new List<NoteEdit>();
|
||||
|
||||
[InverseProperty(nameof(NoteFavorite.Note))]
|
||||
public virtual ICollection<NoteFavorite> NoteFavorites { get; set; } = new List<NoteFavorite>();
|
||||
|
@ -195,7 +205,8 @@ public class Note {
|
|||
[InverseProperty(nameof(NoteReaction.Note))]
|
||||
public virtual ICollection<NoteReaction> NoteReactions { get; set; } = new List<NoteReaction>();
|
||||
|
||||
[InverseProperty(nameof(NoteUnread.Note))] public virtual ICollection<NoteUnread> NoteUnreads { get; set; } = new List<NoteUnread>();
|
||||
[InverseProperty(nameof(NoteUnread.Note))]
|
||||
public virtual ICollection<NoteUnread> NoteUnreads { get; set; } = new List<NoteUnread>();
|
||||
|
||||
[InverseProperty(nameof(NoteWatching.Note))]
|
||||
public virtual ICollection<NoteWatching> NoteWatchings { get; set; } = new List<NoteWatching>();
|
||||
|
@ -203,13 +214,17 @@ public class Note {
|
|||
[InverseProperty(nameof(Notification.Note))]
|
||||
public virtual ICollection<Notification> Notifications { get; set; } = new List<Notification>();
|
||||
|
||||
[InverseProperty(nameof(Tables.Poll.Note))] public virtual Poll? Poll { get; set; }
|
||||
[InverseProperty(nameof(Tables.Poll.Note))]
|
||||
public virtual Poll? Poll { get; set; }
|
||||
|
||||
[InverseProperty(nameof(PollVote.Note))] public virtual ICollection<PollVote> PollVotes { get; set; } = new List<PollVote>();
|
||||
[InverseProperty(nameof(PollVote.Note))]
|
||||
public virtual ICollection<PollVote> PollVotes { get; set; } = new List<PollVote>();
|
||||
|
||||
[InverseProperty(nameof(Tables.PromoNote.Note))] public virtual PromoNote? PromoNote { get; set; }
|
||||
[InverseProperty(nameof(Tables.PromoNote.Note))]
|
||||
public virtual PromoNote? PromoNote { get; set; }
|
||||
|
||||
[InverseProperty(nameof(PromoRead.Note))] public virtual ICollection<PromoRead> PromoReads { get; set; } = new List<PromoRead>();
|
||||
[InverseProperty(nameof(PromoRead.Note))]
|
||||
public virtual ICollection<PromoRead> PromoReads { get; set; } = new List<PromoRead>();
|
||||
|
||||
[ForeignKey("RenoteId")]
|
||||
[InverseProperty(nameof(InverseRenote))]
|
||||
|
@ -225,4 +240,12 @@ public class Note {
|
|||
|
||||
[InverseProperty(nameof(UserNotePin.Note))]
|
||||
public virtual ICollection<UserNotePin> UserNotePins { get; set; } = new List<UserNotePin>();
|
||||
|
||||
[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));
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -275,7 +274,8 @@ public class User {
|
|||
[InverseProperty(nameof(AnnouncementRead.User))]
|
||||
public virtual ICollection<AnnouncementRead> AnnouncementReads { get; set; } = new List<AnnouncementRead>();
|
||||
|
||||
[InverseProperty(nameof(Antenna.User))] public virtual ICollection<Antenna> Antennas { get; set; } = new List<Antenna>();
|
||||
[InverseProperty(nameof(Antenna.User))]
|
||||
public virtual ICollection<Antenna> Antennas { get; set; } = new List<Antenna>();
|
||||
|
||||
[InverseProperty(nameof(App.User))] public virtual ICollection<App> Apps { get; set; } = new List<App>();
|
||||
|
||||
|
@ -294,20 +294,26 @@ public class User {
|
|||
[InverseProperty(nameof(DriveFile.UserBanner))]
|
||||
public virtual DriveFile? Banner { get; set; }
|
||||
|
||||
[InverseProperty(nameof(Blocking.Blockee))]
|
||||
public virtual ICollection<Blocking> BlockingBlockees { get; set; } = new List<Blocking>();
|
||||
[InverseProperty(nameof(Tables.Blocking.Blockee))]
|
||||
public virtual ICollection<Blocking> IncomingBlocks { get; set; } = new List<Blocking>();
|
||||
|
||||
[InverseProperty(nameof(Blocking.Blocker))]
|
||||
public virtual ICollection<Blocking> BlockingBlockers { get; set; } = new List<Blocking>();
|
||||
[InverseProperty(nameof(Tables.Blocking.Blocker))]
|
||||
public virtual ICollection<Blocking> OutgoingBlocks { get; set; } = new List<Blocking>();
|
||||
|
||||
[Projectable] public virtual IEnumerable<User> BlockedBy => IncomingBlocks.Select(p => p.Blocker);
|
||||
|
||||
[Projectable] public virtual IEnumerable<User> Blocking => OutgoingBlocks.Select(p => p.Blockee);
|
||||
|
||||
[InverseProperty(nameof(ChannelFollowing.Follower))]
|
||||
public virtual ICollection<ChannelFollowing> ChannelFollowings { get; set; } = new List<ChannelFollowing>();
|
||||
|
||||
[InverseProperty(nameof(Channel.User))] public virtual ICollection<Channel> Channels { get; set; } = new List<Channel>();
|
||||
[InverseProperty(nameof(Channel.User))]
|
||||
public virtual ICollection<Channel> Channels { get; set; } = new List<Channel>();
|
||||
|
||||
[InverseProperty(nameof(Clip.User))] public virtual ICollection<Clip> Clips { get; set; } = new List<Clip>();
|
||||
|
||||
[InverseProperty(nameof(DriveFile.User))] public virtual ICollection<DriveFile> DriveFiles { get; set; } = new List<DriveFile>();
|
||||
[InverseProperty(nameof(DriveFile.User))]
|
||||
public virtual ICollection<DriveFile> DriveFiles { get; set; } = new List<DriveFile>();
|
||||
|
||||
[InverseProperty(nameof(DriveFolder.User))]
|
||||
public virtual ICollection<DriveFolder> DriveFolders { get; set; } = new List<DriveFolder>();
|
||||
|
@ -324,17 +330,9 @@ public class User {
|
|||
[InverseProperty(nameof(Tables.Following.Follower))]
|
||||
public virtual ICollection<Following> OutgoingFollowRelationships { get; set; } = new List<Following>();
|
||||
|
||||
[Projectable]
|
||||
public virtual IEnumerable<User> Followers => IncomingFollowRelationships.Select(p => p.Follower);
|
||||
[Projectable] public virtual IEnumerable<User> Followers => IncomingFollowRelationships.Select(p => p.Follower);
|
||||
|
||||
[Projectable]
|
||||
public virtual IEnumerable<User> Following => OutgoingFollowRelationships.Select(p => p.Followee);
|
||||
|
||||
[Projectable]
|
||||
public bool IsFollowedBy(User user) => Followers.Contains(user);
|
||||
|
||||
[Projectable]
|
||||
public bool IsFollowing(User user) => Following.Contains(user);
|
||||
[Projectable] public virtual IEnumerable<User> Following => OutgoingFollowRelationships.Select(p => p.Followee);
|
||||
|
||||
[InverseProperty(nameof(GalleryLike.User))]
|
||||
public virtual ICollection<GalleryLike> GalleryLikes { get; set; } = new List<GalleryLike>();
|
||||
|
@ -342,7 +340,8 @@ public class User {
|
|||
[InverseProperty(nameof(GalleryPost.User))]
|
||||
public virtual ICollection<GalleryPost> GalleryPosts { get; set; } = new List<GalleryPost>();
|
||||
|
||||
[InverseProperty(nameof(Tables.HtmlUserCacheEntry.User))] public virtual HtmlUserCacheEntry? HtmlUserCacheEntry { get; set; }
|
||||
[InverseProperty(nameof(Tables.HtmlUserCacheEntry.User))]
|
||||
public virtual HtmlUserCacheEntry? HtmlUserCacheEntry { get; set; }
|
||||
|
||||
[InverseProperty(nameof(MessagingMessage.Recipient))]
|
||||
public virtual ICollection<MessagingMessage> MessagingMessageRecipients { get; set; } =
|
||||
|
@ -354,9 +353,15 @@ public class User {
|
|||
[InverseProperty(nameof(ModerationLog.User))]
|
||||
public virtual ICollection<ModerationLog> ModerationLogs { get; set; } = new List<ModerationLog>();
|
||||
|
||||
[InverseProperty(nameof(Muting.Mutee))] public virtual ICollection<Muting> MutingMutees { get; set; } = new List<Muting>();
|
||||
[InverseProperty(nameof(Tables.Muting.Mutee))]
|
||||
public virtual ICollection<Muting> IncomingMutes { get; set; } = new List<Muting>();
|
||||
|
||||
[InverseProperty(nameof(Muting.Muter))] public virtual ICollection<Muting> MutingMuters { get; set; } = new List<Muting>();
|
||||
[InverseProperty(nameof(Tables.Muting.Muter))]
|
||||
public virtual ICollection<Muting> OutgoingMutes { get; set; } = new List<Muting>();
|
||||
|
||||
[Projectable] public virtual IEnumerable<User> MutedBy => IncomingMutes.Select(p => p.Muter);
|
||||
|
||||
[Projectable] public virtual IEnumerable<User> Muting => OutgoingMutes.Select(p => p.Mutee);
|
||||
|
||||
[InverseProperty(nameof(NoteFavorite.User))]
|
||||
public virtual ICollection<NoteFavorite> NoteFavorites { get; set; } = new List<NoteFavorite>();
|
||||
|
@ -367,7 +372,8 @@ public class User {
|
|||
[InverseProperty(nameof(NoteThreadMuting.User))]
|
||||
public virtual ICollection<NoteThreadMuting> NoteThreadMutings { get; set; } = new List<NoteThreadMuting>();
|
||||
|
||||
[InverseProperty(nameof(NoteUnread.User))] public virtual ICollection<NoteUnread> NoteUnreads { get; set; } = new List<NoteUnread>();
|
||||
[InverseProperty(nameof(NoteUnread.User))]
|
||||
public virtual ICollection<NoteUnread> NoteUnreads { get; set; } = new List<NoteUnread>();
|
||||
|
||||
[InverseProperty(nameof(NoteWatching.User))]
|
||||
public virtual ICollection<NoteWatching> NoteWatchings { get; set; } = new List<NoteWatching>();
|
||||
|
@ -380,9 +386,11 @@ public class User {
|
|||
[InverseProperty(nameof(Notification.Notifier))]
|
||||
public virtual ICollection<Notification> NotificationNotifiers { get; set; } = new List<Notification>();
|
||||
|
||||
[InverseProperty(nameof(OauthToken.User))] public virtual ICollection<OauthToken> OauthTokens { get; set; } = new List<OauthToken>();
|
||||
[InverseProperty(nameof(OauthToken.User))]
|
||||
public virtual ICollection<OauthToken> OauthTokens { get; set; } = new List<OauthToken>();
|
||||
|
||||
[InverseProperty(nameof(PageLike.User))] public virtual ICollection<PageLike> PageLikes { get; set; } = new List<PageLike>();
|
||||
[InverseProperty(nameof(PageLike.User))]
|
||||
public virtual ICollection<PageLike> PageLikes { get; set; } = new List<PageLike>();
|
||||
|
||||
[InverseProperty(nameof(Page.User))] public virtual ICollection<Page> Pages { get; set; } = new List<Page>();
|
||||
|
||||
|
@ -390,9 +398,11 @@ public class User {
|
|||
public virtual ICollection<PasswordResetRequest> PasswordResetRequests { get; set; } =
|
||||
new List<PasswordResetRequest>();
|
||||
|
||||
[InverseProperty(nameof(PollVote.User))] public virtual ICollection<PollVote> PollVotes { get; set; } = new List<PollVote>();
|
||||
[InverseProperty(nameof(PollVote.User))]
|
||||
public virtual ICollection<PollVote> PollVotes { get; set; } = new List<PollVote>();
|
||||
|
||||
[InverseProperty(nameof(PromoRead.User))] public virtual ICollection<PromoRead> PromoReads { get; set; } = new List<PromoRead>();
|
||||
[InverseProperty(nameof(PromoRead.User))]
|
||||
public virtual ICollection<PromoRead> PromoReads { get; set; } = new List<PromoRead>();
|
||||
|
||||
[InverseProperty(nameof(RegistryItem.User))]
|
||||
public virtual ICollection<RegistryItem> RegistryItems { get; set; } = new List<RegistryItem>();
|
||||
|
@ -403,9 +413,11 @@ public class User {
|
|||
[InverseProperty(nameof(RenoteMuting.Muter))]
|
||||
public virtual ICollection<RenoteMuting> RenoteMutingMuters { get; set; } = new List<RenoteMuting>();
|
||||
|
||||
[InverseProperty(nameof(Session.User))] public virtual ICollection<Session> Sessions { get; set; } = new List<Session>();
|
||||
[InverseProperty(nameof(Session.User))]
|
||||
public virtual ICollection<Session> Sessions { get; set; } = new List<Session>();
|
||||
|
||||
[InverseProperty(nameof(Signin.User))] public virtual ICollection<Signin> Signins { get; set; } = new List<Signin>();
|
||||
[InverseProperty(nameof(Signin.User))]
|
||||
public virtual ICollection<Signin> Signins { get; set; } = new List<Signin>();
|
||||
|
||||
[InverseProperty(nameof(SwSubscription.User))]
|
||||
public virtual ICollection<SwSubscription> SwSubscriptions { get; set; } = new List<SwSubscription>();
|
||||
|
@ -417,24 +429,48 @@ public class User {
|
|||
[InverseProperty(nameof(UserGroupMember.User))]
|
||||
public virtual ICollection<UserGroupMember> UserGroupMemberships { get; set; } = new List<UserGroupMember>();
|
||||
|
||||
[InverseProperty(nameof(UserGroup.User))] public virtual ICollection<UserGroup> UserGroups { get; set; } = new List<UserGroup>();
|
||||
[InverseProperty(nameof(UserGroup.User))]
|
||||
public virtual ICollection<UserGroup> UserGroups { get; set; } = new List<UserGroup>();
|
||||
|
||||
[InverseProperty(nameof(Tables.UserKeypair.User))] public virtual UserKeypair? UserKeypair { get; set; }
|
||||
[InverseProperty(nameof(Tables.UserKeypair.User))]
|
||||
public virtual UserKeypair? UserKeypair { get; set; }
|
||||
|
||||
[InverseProperty(nameof(UserListMember.User))]
|
||||
public virtual ICollection<UserListMember> UserListMembers { get; set; } = new List<UserListMember>();
|
||||
|
||||
[InverseProperty(nameof(UserList.User))] public virtual ICollection<UserList> UserLists { get; set; } = new List<UserList>();
|
||||
[InverseProperty(nameof(UserList.User))]
|
||||
public virtual ICollection<UserList> UserLists { get; set; } = new List<UserList>();
|
||||
|
||||
[InverseProperty(nameof(UserNotePin.User))]
|
||||
public virtual ICollection<UserNotePin> UserNotePins { get; set; } = new List<UserNotePin>();
|
||||
|
||||
[InverseProperty(nameof(Tables.UserProfile.User))] public virtual UserProfile? UserProfile { get; set; }
|
||||
[InverseProperty(nameof(Tables.UserProfile.User))]
|
||||
public virtual UserProfile? UserProfile { get; set; }
|
||||
|
||||
[InverseProperty(nameof(Tables.UserPublickey.User))] public virtual UserPublickey? UserPublickey { get; set; }
|
||||
[InverseProperty(nameof(Tables.UserPublickey.User))]
|
||||
public virtual UserPublickey? UserPublickey { get; set; }
|
||||
|
||||
[InverseProperty(nameof(UserSecurityKey.User))]
|
||||
public virtual ICollection<UserSecurityKey> UserSecurityKeys { get; set; } = new List<UserSecurityKey>();
|
||||
|
||||
[InverseProperty(nameof(Webhook.User))] public virtual ICollection<Webhook> Webhooks { get; set; } = new List<Webhook>();
|
||||
[InverseProperty(nameof(Webhook.User))]
|
||||
public virtual ICollection<Webhook> Webhooks { get; set; } = new List<Webhook>();
|
||||
|
||||
[Projectable]
|
||||
public bool IsBlockedBy(User user) => BlockedBy.Contains(user);
|
||||
|
||||
[Projectable]
|
||||
public bool IsBlocking(User user) => Blocking.Contains(user);
|
||||
|
||||
[Projectable]
|
||||
public bool IsFollowedBy(User user) => Followers.Contains(user);
|
||||
|
||||
[Projectable]
|
||||
public bool IsFollowing(User user) => Following.Contains(user);
|
||||
|
||||
[Projectable]
|
||||
public bool IsMutedBy(User user) => MutedBy.Contains(user);
|
||||
|
||||
[Projectable]
|
||||
public bool IsMuting(User user) => Muting.Contains(user);
|
||||
}
|
|
@ -53,6 +53,35 @@ public static class NoteQueryableExtensions {
|
|||
return query.Where(note => note.User == user || note.User.IsFollowedBy(user));
|
||||
}
|
||||
|
||||
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 query.Where(note => note.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 ||
|
||||
(!note.Renote.User.IsBlockedBy(user) && !note.Renote.User.IsBlocking(user)))
|
||||
.Where(note => 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
|
||||
|
||||
return query.Where(note => !note.User.IsMuting(user))
|
||||
.Where(note => note.Renote == null || !note.Renote.User.IsMuting(user))
|
||||
.Where(note => note.Reply == null || !note.Reply.User.IsMuting(user));
|
||||
}
|
||||
|
||||
public static IQueryable<Note> FilterHiddenListMembers(this IQueryable<Note> query, User user) {
|
||||
return query.Where(note => note.User.UserListMembers.Any(p => p.UserList.User == user &&
|
||||
p.UserList.HideFromHomeTl));
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<Status>> RenderAllForMastodonAsync(
|
||||
this IQueryable<Note> notes, NoteRenderer renderer) {
|
||||
var list = await notes.ToListAsync();
|
||||
|
|
Loading…
Add table
Reference in a new issue