[backend] Refactor inverse properties; add projectable computed properties to the User class

This commit is contained in:
Laura Hausmann 2024-02-02 22:59:17 +01:00
parent b015c464dd
commit af7a776337
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
64 changed files with 256 additions and 241 deletions

View file

@ -1,15 +1,12 @@
using Iceshrimp.Backend.Controllers.Attributes;
using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Helpers;
using Iceshrimp.Backend.Core.Middleware;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
namespace Iceshrimp.Backend.Controllers.Mastodon;
@ -28,13 +25,13 @@ public class MastodonTimelineController(DatabaseContext db, NoteRenderer noteRen
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Status>))]
public async Task<IActionResult> GetHomeTimeline() {
var user = HttpContext.GetOauthUser() ?? throw new GracefulException("Failed to get user from HttpContext");
var notes = db.Notes
.WithIncludes()
.IsFollowedBy(user)
.OrderByIdDesc()
.Take(40);
var res = await db.Notes
.WithIncludes()
.FilterByFollowingAndOwn(user)
.OrderByIdDesc()
.Take(40)
.RenderAllForMastodonAsync(noteRenderer);
var res = await notes.RenderAllForMastodonAsync(noteRenderer);
return Ok(res);
}
@ -43,13 +40,13 @@ public class MastodonTimelineController(DatabaseContext db, NoteRenderer noteRen
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<Status>))]
public async Task<IActionResult> GetPublicTimeline() {
var notes = db.Notes
.WithIncludes()
.HasVisibility(Note.NoteVisibility.Public)
.OrderByIdDesc()
.Take(40);
var res = await db.Notes
.WithIncludes()
.HasVisibility(Note.NoteVisibility.Public)
.OrderByIdDesc()
.Take(40)
.RenderAllForMastodonAsync(noteRenderer);
var res = await notes.RenderAllForMastodonAsync(noteRenderer);
return Ok(res);
}
}

View file

@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using EntityFrameworkCore.Projectables.Infrastructure;
using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Database.Tables;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
@ -106,6 +107,9 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
public static void Configure(DbContextOptionsBuilder optionsBuilder, NpgsqlDataSource dataSource) {
optionsBuilder.UseNpgsql(dataSource);
optionsBuilder.UseProjectables(options => {
options.CompatibilityMode(CompatibilityMode.Limited);
});
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
@ -348,9 +352,9 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
entity.Property(e => e.FollowerSharedInbox).HasComment("[Denormalized]");
entity.Property(e => e.RequestId).HasComment("id of Follow Activity.");
entity.HasOne(d => d.Followee).WithMany(p => p.FollowRequestFollowees);
entity.HasOne(d => d.Followee).WithMany(p => p.IncomingFollowRequests);
entity.HasOne(d => d.Follower).WithMany(p => p.FollowRequestFollowers);
entity.HasOne(d => d.Follower).WithMany(p => p.OutgoingFollowRequests);
});
modelBuilder.Entity<Following>(entity => {
@ -364,9 +368,9 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options)
entity.Property(e => e.FollowerInbox).HasComment("[Denormalized]");
entity.Property(e => e.FollowerSharedInbox).HasComment("[Denormalized]");
entity.HasOne(d => d.Followee).WithMany(p => p.FollowingFollowees);
entity.HasOne(d => d.Followee).WithMany(p => p.IncomingFollowRelationships);
entity.HasOne(d => d.Follower).WithMany(p => p.FollowingFollowers);
entity.HasOne(d => d.Follower).WithMany(p => p.OutgoingFollowRelationships);
});
modelBuilder.Entity<GalleryLike>(entity => {

View file

@ -58,14 +58,14 @@ public class AbuseUserReport {
[Column("forwarded")] public bool Forwarded { get; set; }
[ForeignKey("AssigneeId")]
[InverseProperty("AbuseUserReportAssignees")]
[InverseProperty(nameof(User.AbuseUserReportAssignees))]
public virtual User? Assignee { get; set; }
[ForeignKey("ReporterId")]
[InverseProperty("AbuseUserReportReporters")]
[InverseProperty(nameof(User.AbuseUserReportReporters))]
public virtual User Reporter { get; set; } = null!;
[ForeignKey("TargetUserId")]
[InverseProperty("AbuseUserReportTargetUsers")]
[InverseProperty(nameof(User.AbuseUserReportTargetUsers))]
public virtual User TargetUser { get; set; } = null!;
}

View file

@ -51,13 +51,13 @@ public class AccessToken {
[Column("fetched")] public bool Fetched { get; set; }
[ForeignKey("AppId")]
[InverseProperty("AccessTokens")]
[InverseProperty(nameof(Tables.App.AccessTokens))]
public virtual App? App { get; set; }
[InverseProperty("AppAccessToken")]
[InverseProperty(nameof(Notification.AppAccessToken))]
public virtual ICollection<Notification> Notifications { get; set; } = new List<Notification>();
[ForeignKey("UserId")]
[InverseProperty("AccessTokens")]
[InverseProperty(nameof(Tables.User.AccessTokens))]
public virtual User User { get; set; } = null!;
}

View file

@ -36,6 +36,6 @@ public class Announcement {
[Column("isGoodNews")] public bool IsGoodNews { get; set; }
[InverseProperty("Announcement")]
[InverseProperty(nameof(AnnouncementRead.Announcement))]
public virtual ICollection<AnnouncementRead> AnnouncementReads { get; set; } = new List<AnnouncementRead>();
}

View file

@ -27,10 +27,10 @@ public class AnnouncementRead {
public DateTime CreatedAt { get; set; }
[ForeignKey("AnnouncementId")]
[InverseProperty("AnnouncementReads")]
[InverseProperty(nameof(Tables.Announcement.AnnouncementReads))]
public virtual Announcement Announcement { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("AnnouncementReads")]
[InverseProperty(nameof(Tables.User.AnnouncementReads))]
public virtual User User { get; set; } = null!;
}

View file

@ -68,15 +68,15 @@ public class Antenna {
public string Instances { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("Antennas")]
[InverseProperty(nameof(Tables.User.Antennas))]
public virtual User User { get; set; } = null!;
[ForeignKey("UserGroupMemberId")]
[InverseProperty("Antennas")]
[InverseProperty(nameof(Tables.UserGroupMember.Antennas))]
public virtual UserGroupMember? UserGroupMember { get; set; }
[ForeignKey("UserListId")]
[InverseProperty("Antennas")]
[InverseProperty(nameof(Tables.UserList.Antennas))]
public virtual UserList? UserList { get; set; }
[PgName("antenna_src_enum")]

View file

@ -61,13 +61,13 @@ public class App {
[StringLength(512)]
public string? CallbackUrl { get; set; }
[InverseProperty("App")]
[InverseProperty(nameof(AccessToken.App))]
public virtual ICollection<AccessToken> AccessTokens { get; set; } = new List<AccessToken>();
[InverseProperty("App")]
[InverseProperty(nameof(AuthSession.App))]
public virtual ICollection<AuthSession> AuthSessions { get; set; } = new List<AuthSession>();
[ForeignKey("UserId")]
[InverseProperty("Apps")]
[InverseProperty(nameof(Tables.User.Apps))]
public virtual User? User { get; set; }
}

View file

@ -40,6 +40,6 @@ public class AttestationChallenge {
public bool RegistrationChallenge { get; set; }
[ForeignKey("UserId")]
[InverseProperty("AttestationChallenges")]
[InverseProperty(nameof(Tables.User.AttestationChallenges))]
public virtual User User { get; set; } = null!;
}

View file

@ -25,10 +25,10 @@ public class AuthSession {
[Column("appId")] [StringLength(32)] public string AppId { get; set; } = null!;
[ForeignKey("AppId")]
[InverseProperty("AuthSessions")]
[InverseProperty(nameof(Tables.App.AuthSessions))]
public virtual App App { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("AuthSessions")]
[InverseProperty(nameof(Tables.User.AuthSessions))]
public virtual User? User { get; set; }
}

View file

@ -36,10 +36,10 @@ public class Blocking {
public string BlockerId { get; set; } = null!;
[ForeignKey("BlockeeId")]
[InverseProperty("BlockingBlockees")]
[InverseProperty(nameof(User.BlockingBlockees))]
public virtual User Blockee { get; set; } = null!;
[ForeignKey("BlockerId")]
[InverseProperty("BlockingBlockers")]
[InverseProperty(nameof(User.BlockingBlockers))]
public virtual User Blocker { get; set; } = null!;
}

View file

@ -65,18 +65,18 @@ public class Channel {
public int UsersCount { get; set; }
[ForeignKey("BannerId")]
[InverseProperty("Channels")]
[InverseProperty(nameof(DriveFile.Channels))]
public virtual DriveFile? Banner { get; set; }
[InverseProperty("Followee")]
[InverseProperty(nameof(ChannelFollowing.Followee))]
public virtual ICollection<ChannelFollowing> ChannelFollowings { get; set; } = new List<ChannelFollowing>();
[InverseProperty("Channel")]
[InverseProperty(nameof(ChannelNotePin.Channel))]
public virtual ICollection<ChannelNotePin> ChannelNotePins { get; set; } = new List<ChannelNotePin>();
[InverseProperty("Channel")] public virtual ICollection<Note> Notes { get; set; } = new List<Note>();
[InverseProperty(nameof(Note.Channel))] public virtual ICollection<Note> Notes { get; set; } = new List<Note>();
[ForeignKey("UserId")]
[InverseProperty("Channels")]
[InverseProperty(nameof(Tables.User.Channels))]
public virtual User? User { get; set; }
}

View file

@ -36,10 +36,10 @@ public class ChannelFollowing {
public string FollowerId { get; set; } = null!;
[ForeignKey("FolloweeId")]
[InverseProperty("ChannelFollowings")]
[InverseProperty(nameof(Channel.ChannelFollowings))]
public virtual Channel Followee { get; set; } = null!;
[ForeignKey("FollowerId")]
[InverseProperty("ChannelFollowings")]
[InverseProperty(nameof(User.ChannelFollowings))]
public virtual User Follower { get; set; } = null!;
}

View file

@ -26,10 +26,10 @@ public class ChannelNotePin {
[Column("noteId")] [StringLength(32)] public string NoteId { get; set; } = null!;
[ForeignKey("ChannelId")]
[InverseProperty("ChannelNotePins")]
[InverseProperty(nameof(Tables.Channel.ChannelNotePins))]
public virtual Channel Channel { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("ChannelNotePins")]
[InverseProperty(nameof(Tables.Note.ChannelNotePins))]
public virtual Note Note { get; set; } = null!;
}

View file

@ -41,9 +41,9 @@ public class Clip {
[StringLength(2048)]
public string? Description { get; set; }
[InverseProperty("Clip")] public virtual ICollection<ClipNote> ClipNotes { get; set; } = new List<ClipNote>();
[InverseProperty(nameof(ClipNote.Clip))] public virtual ICollection<ClipNote> ClipNotes { get; set; } = new List<ClipNote>();
[ForeignKey("UserId")]
[InverseProperty("Clips")]
[InverseProperty(nameof(Tables.User.Clips))]
public virtual User User { get; set; } = null!;
}

View file

@ -29,10 +29,10 @@ public class ClipNote {
public string ClipId { get; set; } = null!;
[ForeignKey("ClipId")]
[InverseProperty("ClipNotes")]
[InverseProperty(nameof(Tables.Clip.ClipNotes))]
public virtual Clip Clip { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("ClipNotes")]
[InverseProperty(nameof(Tables.Note.ClipNotes))]
public virtual Note Note { get; set; } = null!;
}

View file

@ -165,22 +165,22 @@ public class DriveFile {
[StringLength(128)]
public string? RequestIp { get; set; }
[InverseProperty("Banner")] public virtual ICollection<Channel> Channels { get; set; } = new List<Channel>();
[InverseProperty(nameof(Channel.Banner))] public virtual ICollection<Channel> Channels { get; set; } = new List<Channel>();
[ForeignKey("FolderId")]
[InverseProperty("DriveFiles")]
[InverseProperty(nameof(DriveFolder.DriveFiles))]
public virtual DriveFolder? Folder { get; set; }
[InverseProperty("File")]
[InverseProperty(nameof(MessagingMessage.File))]
public virtual ICollection<MessagingMessage> MessagingMessages { get; set; } = new List<MessagingMessage>();
[InverseProperty("EyeCatchingImage")] public virtual ICollection<Page> Pages { get; set; } = new List<Page>();
[InverseProperty(nameof(Page.EyeCatchingImage))] public virtual ICollection<Page> Pages { get; set; } = new List<Page>();
[ForeignKey("UserId")]
[InverseProperty("DriveFiles")]
[InverseProperty(nameof(Tables.User.DriveFiles))]
public virtual User? User { get; set; }
[InverseProperty("Avatar")] public virtual User? UserAvatar { get; set; }
[InverseProperty(nameof(Tables.User.Avatar))] public virtual User? UserAvatar { get; set; }
[InverseProperty("Banner")] public virtual User? UserBanner { get; set; }
[InverseProperty(nameof(Tables.User.Banner))] public virtual User? UserBanner { get; set; }
}

View file

@ -41,16 +41,16 @@ public class DriveFolder {
[StringLength(32)]
public string? ParentId { get; set; }
[InverseProperty("Folder")] public virtual ICollection<DriveFile> DriveFiles { get; set; } = new List<DriveFile>();
[InverseProperty(nameof(DriveFile.Folder))] public virtual ICollection<DriveFile> DriveFiles { get; set; } = new List<DriveFile>();
[InverseProperty("Parent")]
[InverseProperty(nameof(Parent))]
public virtual ICollection<DriveFolder> InverseParent { get; set; } = new List<DriveFolder>();
[ForeignKey("ParentId")]
[InverseProperty("InverseParent")]
[InverseProperty(nameof(InverseParent))]
public virtual DriveFolder? Parent { get; set; }
[ForeignKey("UserId")]
[InverseProperty("DriveFolders")]
[InverseProperty(nameof(Tables.User.DriveFolders))]
public virtual User? User { get; set; }
}

View file

@ -84,13 +84,13 @@ public class FollowRequest {
public string? FolloweeSharedInbox { get; set; }
[ForeignKey("FolloweeId")]
[InverseProperty("FollowRequestFollowees")]
[InverseProperty(nameof(User.IncomingFollowRequests))]
public virtual User Followee { get; set; } = null!;
[ForeignKey("FollowerId")]
[InverseProperty("FollowRequestFollowers")]
[InverseProperty(nameof(User.OutgoingFollowRequests))]
public virtual User Follower { get; set; } = null!;
[InverseProperty("FollowRequest")]
[InverseProperty(nameof(Notification.FollowRequest))]
public virtual ICollection<Notification> Notifications { get; set; } = new List<Notification>();
}

View file

@ -80,10 +80,10 @@ public class Following {
public string? FolloweeSharedInbox { get; set; }
[ForeignKey("FolloweeId")]
[InverseProperty("FollowingFollowees")]
[InverseProperty(nameof(User.IncomingFollowRelationships))]
public virtual User Followee { get; set; } = null!;
[ForeignKey("FollowerId")]
[InverseProperty("FollowingFollowers")]
[InverseProperty(nameof(User.OutgoingFollowRelationships))]
public virtual User Follower { get; set; } = null!;
}

View file

@ -20,10 +20,10 @@ public class GalleryLike {
[Column("postId")] [StringLength(32)] public string PostId { get; set; } = null!;
[ForeignKey("PostId")]
[InverseProperty("GalleryLikes")]
[InverseProperty(nameof(GalleryPost.GalleryLikes))]
public virtual GalleryPost Post { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("GalleryLikes")]
[InverseProperty(nameof(Tables.User.GalleryLikes))]
public virtual User User { get; set; } = null!;
}

View file

@ -57,10 +57,10 @@ public class GalleryPost {
[Column("tags", TypeName = "character varying(128)[]")]
public List<string> Tags { get; set; } = null!;
[InverseProperty("Post")]
[InverseProperty(nameof(GalleryLike.Post))]
public virtual ICollection<GalleryLike> GalleryLikes { get; set; } = new List<GalleryLike>();
[ForeignKey("UserId")]
[InverseProperty("GalleryPosts")]
[InverseProperty(nameof(Tables.User.GalleryPosts))]
public virtual User User { get; set; } = null!;
}

View file

@ -15,6 +15,6 @@ public class HtmlNoteCacheEntry {
[Column("content")] public string? Content { get; set; }
[ForeignKey("NoteId")]
[InverseProperty("HtmlNoteCacheEntry")]
[InverseProperty(nameof(Tables.Note.HtmlNoteCacheEntry))]
public virtual Note Note { get; set; } = null!;
}

View file

@ -17,6 +17,6 @@ public class HtmlUserCacheEntry {
[Column("fields", TypeName = "jsonb")] public string Fields { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("HtmlUserCacheEntry")]
[InverseProperty(nameof(Tables.User.HtmlUserCacheEntry))]
public virtual User User { get; set; } = null!;
}

View file

@ -54,18 +54,18 @@ public class MessagingMessage {
[Column("uri")] [StringLength(512)] public string? Uri { get; set; }
[ForeignKey("FileId")]
[InverseProperty("MessagingMessages")]
[InverseProperty(nameof(DriveFile.MessagingMessages))]
public virtual DriveFile? File { get; set; }
[ForeignKey("GroupId")]
[InverseProperty("MessagingMessages")]
[InverseProperty(nameof(UserGroup.MessagingMessages))]
public virtual UserGroup? Group { get; set; }
[ForeignKey("RecipientId")]
[InverseProperty("MessagingMessageRecipients")]
[InverseProperty(nameof(Tables.User.MessagingMessageRecipients))]
public virtual User? Recipient { get; set; }
[ForeignKey("UserId")]
[InverseProperty("MessagingMessageUsers")]
[InverseProperty(nameof(Tables.User.MessagingMessageUsers))]
public virtual User User { get; set; } = null!;
}

View file

@ -25,6 +25,6 @@ public class ModerationLog {
[Column("info", TypeName = "jsonb")] public string Info { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("ModerationLogs")]
[InverseProperty(nameof(Tables.User.ModerationLogs))]
public virtual User User { get; set; } = null!;
}

View file

@ -39,10 +39,10 @@ public class Muting {
[Column("expiresAt")] public DateTime? ExpiresAt { get; set; }
[ForeignKey("MuteeId")]
[InverseProperty("MutingMutees")]
[InverseProperty(nameof(User.MutingMutees))]
public virtual User Mutee { get; set; } = null!;
[ForeignKey("MuterId")]
[InverseProperty("MutingMuters")]
[InverseProperty(nameof(User.MutingMuters))]
public virtual User Muter { get; set; } = null!;
}

View file

@ -173,56 +173,56 @@ public class Note {
public DateTime? UpdatedAt { get; set; }
[ForeignKey("ChannelId")]
[InverseProperty("Notes")]
[InverseProperty(nameof(Tables.Channel.Notes))]
public virtual Channel? Channel { get; set; }
[InverseProperty("Note")]
[InverseProperty(nameof(ChannelNotePin.Note))]
public virtual ICollection<ChannelNotePin> ChannelNotePins { get; set; } = new List<ChannelNotePin>();
[InverseProperty("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("Note")] public virtual HtmlNoteCacheEntry? HtmlNoteCacheEntry { get; set; }
[InverseProperty(nameof(Tables.HtmlNoteCacheEntry.Note))] public virtual HtmlNoteCacheEntry? HtmlNoteCacheEntry { get; set; }
[InverseProperty("Renote")] public virtual ICollection<Note> InverseRenote { get; set; } = new List<Note>();
[InverseProperty(nameof(Renote))] public virtual ICollection<Note> InverseRenote { get; set; } = new List<Note>();
[InverseProperty("Reply")] public virtual ICollection<Note> InverseReply { get; set; } = new List<Note>();
[InverseProperty(nameof(Reply))] public virtual ICollection<Note> InverseReply { get; set; } = new List<Note>();
[InverseProperty("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("Note")]
[InverseProperty(nameof(NoteFavorite.Note))]
public virtual ICollection<NoteFavorite> NoteFavorites { get; set; } = new List<NoteFavorite>();
[InverseProperty("Note")]
[InverseProperty(nameof(NoteReaction.Note))]
public virtual ICollection<NoteReaction> NoteReactions { get; set; } = new List<NoteReaction>();
[InverseProperty("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("Note")]
[InverseProperty(nameof(NoteWatching.Note))]
public virtual ICollection<NoteWatching> NoteWatchings { get; set; } = new List<NoteWatching>();
[InverseProperty("Note")]
[InverseProperty(nameof(Notification.Note))]
public virtual ICollection<Notification> Notifications { get; set; } = new List<Notification>();
[InverseProperty("Note")] public virtual Poll? Poll { get; set; }
[InverseProperty(nameof(Tables.Poll.Note))] public virtual Poll? Poll { get; set; }
[InverseProperty("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("Note")] public virtual PromoNote? PromoNote { get; set; }
[InverseProperty(nameof(Tables.PromoNote.Note))] public virtual PromoNote? PromoNote { get; set; }
[InverseProperty("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("InverseRenote")]
[InverseProperty(nameof(InverseRenote))]
public virtual Note? Renote { get; set; }
[ForeignKey("ReplyId")]
[InverseProperty("InverseReply")]
[InverseProperty(nameof(InverseReply))]
public virtual Note? Reply { get; set; }
[ForeignKey("UserId")]
[InverseProperty("Notes")]
[InverseProperty(nameof(Tables.User.Notes))]
public virtual User User { get; set; } = null!;
[InverseProperty("Note")]
[InverseProperty(nameof(UserNotePin.Note))]
public virtual ICollection<UserNotePin> UserNotePins { get; set; } = new List<UserNotePin>();
}

View file

@ -33,6 +33,6 @@ public class NoteEdit {
public DateTime UpdatedAt { get; set; }
[ForeignKey("NoteId")]
[InverseProperty("NoteEdits")]
[InverseProperty(nameof(Tables.Note.NoteEdits))]
public virtual Note Note { get; set; } = null!;
}

View file

@ -24,10 +24,10 @@ public class NoteFavorite {
[Column("noteId")] [StringLength(32)] public string NoteId { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("NoteFavorites")]
[InverseProperty(nameof(Tables.Note.NoteFavorites))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("NoteFavorites")]
[InverseProperty(nameof(Tables.User.NoteFavorites))]
public virtual User User { get; set; } = null!;
}

View file

@ -30,10 +30,10 @@ public class NoteReaction {
public string Reaction { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("NoteReactions")]
[InverseProperty(nameof(Tables.Note.NoteReactions))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("NoteReactions")]
[InverseProperty(nameof(Tables.User.NoteReactions))]
public virtual User User { get; set; } = null!;
}

View file

@ -23,6 +23,6 @@ public class NoteThreadMuting {
public string ThreadId { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("NoteThreadMutings")]
[InverseProperty(nameof(Tables.User.NoteThreadMutings))]
public virtual User User { get; set; } = null!;
}

View file

@ -41,10 +41,10 @@ public class NoteUnread {
public string? NoteChannelId { get; set; }
[ForeignKey("NoteId")]
[InverseProperty("NoteUnreads")]
[InverseProperty(nameof(Tables.Note.NoteUnreads))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("NoteUnreads")]
[InverseProperty(nameof(Tables.User.NoteUnreads))]
public virtual User User { get; set; } = null!;
}

View file

@ -44,10 +44,10 @@ public class NoteWatching {
public string NoteUserId { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("NoteWatchings")]
[InverseProperty(nameof(Tables.Note.NoteWatchings))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("NoteWatchings")]
[InverseProperty(nameof(Tables.User.NoteWatchings))]
public virtual User User { get; set; } = null!;
}

View file

@ -79,27 +79,27 @@ public class Notification {
public string? AppAccessTokenId { get; set; }
[ForeignKey("AppAccessTokenId")]
[InverseProperty("Notifications")]
[InverseProperty(nameof(AccessToken.Notifications))]
public virtual AccessToken? AppAccessToken { get; set; }
[ForeignKey("FollowRequestId")]
[InverseProperty("Notifications")]
[InverseProperty(nameof(Tables.FollowRequest.Notifications))]
public virtual FollowRequest? FollowRequest { get; set; }
[ForeignKey("NoteId")]
[InverseProperty("Notifications")]
[InverseProperty(nameof(Tables.Note.Notifications))]
public virtual Note? Note { get; set; }
[ForeignKey("NotifieeId")]
[InverseProperty("NotificationNotifiees")]
[InverseProperty(nameof(User.NotificationNotifiees))]
public virtual User Notifiee { get; set; } = null!;
[ForeignKey("NotifierId")]
[InverseProperty("NotificationNotifiers")]
[InverseProperty(nameof(User.NotificationNotifiers))]
public virtual User? Notifier { get; set; }
[ForeignKey("UserGroupInvitationId")]
[InverseProperty("Notifications")]
[InverseProperty(nameof(Tables.UserGroupInvitation.Notifications))]
public virtual UserGroupInvitation? UserGroupInvitation { get; set; }
[PgName("notification_type_enum")]

View file

@ -58,5 +58,5 @@ public class OauthApp {
[Column("redirectUris", TypeName = "character varying(512)[]")]
public List<string> RedirectUris { get; set; } = null!;
[InverseProperty("App")] public virtual ICollection<OauthToken> OauthTokens { get; set; } = new List<OauthToken>();
[InverseProperty(nameof(OauthToken.App))] public virtual ICollection<OauthToken> OauthTokens { get; set; } = new List<OauthToken>();
}

View file

@ -57,10 +57,10 @@ public class OauthToken {
public string RedirectUri { get; set; } = null!;
[ForeignKey("AppId")]
[InverseProperty("OauthTokens")]
[InverseProperty(nameof(OauthApp.OauthTokens))]
public virtual OauthApp App { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("OauthTokens")]
[InverseProperty(nameof(Tables.User.OauthTokens))]
public virtual User User { get; set; } = null!;
}

View file

@ -75,16 +75,16 @@ public class Page {
[Column("isPublic")] public bool IsPublic { get; set; }
[ForeignKey("EyeCatchingImageId")]
[InverseProperty("Pages")]
[InverseProperty(nameof(DriveFile.Pages))]
public virtual DriveFile? EyeCatchingImage { get; set; }
[InverseProperty("Page")] public virtual ICollection<PageLike> PageLikes { get; set; } = new List<PageLike>();
[InverseProperty(nameof(PageLike.Page))] public virtual ICollection<PageLike> PageLikes { get; set; } = new List<PageLike>();
[ForeignKey("UserId")]
[InverseProperty("Pages")]
[InverseProperty(nameof(Tables.User.Pages))]
public virtual User User { get; set; } = null!;
[InverseProperty("PinnedPage")] public virtual UserProfile? UserProfile { get; set; }
[InverseProperty(nameof(Tables.UserProfile.PinnedPage))] public virtual UserProfile? UserProfile { get; set; }
[PgName("page_visibility_enum")]
public enum PageVisibility {

View file

@ -20,10 +20,10 @@ public class PageLike {
[Column("pageId")] [StringLength(32)] public string PageId { get; set; } = null!;
[ForeignKey("PageId")]
[InverseProperty("PageLikes")]
[InverseProperty(nameof(Tables.Page.PageLikes))]
public virtual Page Page { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("PageLikes")]
[InverseProperty(nameof(Tables.User.PageLikes))]
public virtual User User { get; set; } = null!;
}

View file

@ -20,6 +20,6 @@ public class PasswordResetRequest {
[Column("userId")] [StringLength(32)] public string UserId { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("PasswordResetRequests")]
[InverseProperty(nameof(Tables.User.PasswordResetRequests))]
public virtual User User { get; set; } = null!;
}

View file

@ -38,7 +38,7 @@ public class Poll {
public string? UserHost { get; set; }
[ForeignKey("NoteId")]
[InverseProperty("Poll")]
[InverseProperty(nameof(Tables.Note.Poll))]
public virtual Note Note { get; set; } = null!;
/// <summary>

View file

@ -28,10 +28,10 @@ public class PollVote {
[Column("choice")] public int Choice { get; set; }
[ForeignKey("NoteId")]
[InverseProperty("PollVotes")]
[InverseProperty(nameof(Tables.Note.PollVotes))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("PollVotes")]
[InverseProperty(nameof(Tables.User.PollVotes))]
public virtual User User { get; set; } = null!;
}

View file

@ -22,6 +22,6 @@ public class PromoNote {
public string UserId { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("PromoNote")]
[InverseProperty(nameof(Tables.Note.PromoNote))]
public virtual Note Note { get; set; } = null!;
}

View file

@ -24,10 +24,10 @@ public class PromoRead {
[Column("noteId")] [StringLength(32)] public string NoteId { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("PromoReads")]
[InverseProperty(nameof(Tables.Note.PromoReads))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("PromoReads")]
[InverseProperty(nameof(Tables.User.PromoReads))]
public virtual User User { get; set; } = null!;
}

View file

@ -52,6 +52,6 @@ public class RegistryItem {
public string? Value { get; set; }
[ForeignKey("UserId")]
[InverseProperty("RegistryItems")]
[InverseProperty(nameof(Tables.User.RegistryItems))]
public virtual User User { get; set; } = null!;
}

View file

@ -36,10 +36,10 @@ public class RenoteMuting {
public string MuterId { get; set; } = null!;
[ForeignKey("MuteeId")]
[InverseProperty("RenoteMutingMutees")]
[InverseProperty(nameof(User.RenoteMutingMutees))]
public virtual User Mutee { get; set; } = null!;
[ForeignKey("MuterId")]
[InverseProperty("RenoteMutingMuters")]
[InverseProperty(nameof(User.RenoteMutingMuters))]
public virtual User Muter { get; set; } = null!;
}

View file

@ -34,6 +34,6 @@ public class Session {
public bool Active { get; set; }
[ForeignKey("UserId")]
[InverseProperty("Sessions")]
[InverseProperty(nameof(Tables.User.Sessions))]
public virtual User User { get; set; } = null!;
}

View file

@ -28,6 +28,6 @@ public class Signin {
[Column("success")] public bool Success { get; set; }
[ForeignKey("UserId")]
[InverseProperty("Signins")]
[InverseProperty(nameof(Tables.User.Signins))]
public virtual User User { get; set; } = null!;
}

View file

@ -29,6 +29,6 @@ public class SwSubscription {
[Column("sendReadMessage")] public bool SendReadMessage { get; set; }
[ForeignKey("UserId")]
[InverseProperty("SwSubscriptions")]
[InverseProperty(nameof(Tables.User.SwSubscriptions))]
public virtual User User { get; set; } = null!;
}

View file

@ -1,5 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using EntityFrameworkCore.Projectables;
using Microsoft.EntityFrameworkCore;
namespace Iceshrimp.Backend.Core.Database.Tables;
@ -258,169 +260,181 @@ public class User {
[StringLength(128)]
public string? BannerBlurhash { get; set; }
[InverseProperty("Assignee")]
[InverseProperty(nameof(AbuseUserReport.Assignee))]
public virtual ICollection<AbuseUserReport> AbuseUserReportAssignees { get; set; } = new List<AbuseUserReport>();
[InverseProperty("Reporter")]
[InverseProperty(nameof(AbuseUserReport.Reporter))]
public virtual ICollection<AbuseUserReport> AbuseUserReportReporters { get; set; } = new List<AbuseUserReport>();
[InverseProperty("TargetUser")]
[InverseProperty(nameof(AbuseUserReport.TargetUser))]
public virtual ICollection<AbuseUserReport> AbuseUserReportTargetUsers { get; set; } = new List<AbuseUserReport>();
[InverseProperty("User")]
[InverseProperty(nameof(AccessToken.User))]
public virtual ICollection<AccessToken> AccessTokens { get; set; } = new List<AccessToken>();
[InverseProperty("User")]
[InverseProperty(nameof(AnnouncementRead.User))]
public virtual ICollection<AnnouncementRead> AnnouncementReads { get; set; } = new List<AnnouncementRead>();
[InverseProperty("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("User")] public virtual ICollection<App> Apps { get; set; } = new List<App>();
[InverseProperty(nameof(App.User))] public virtual ICollection<App> Apps { get; set; } = new List<App>();
[InverseProperty("User")]
[InverseProperty(nameof(AttestationChallenge.User))]
public virtual ICollection<AttestationChallenge> AttestationChallenges { get; set; } =
new List<AttestationChallenge>();
[InverseProperty("User")]
[InverseProperty(nameof(AuthSession.User))]
public virtual ICollection<AuthSession> AuthSessions { get; set; } = new List<AuthSession>();
[ForeignKey("AvatarId")]
[InverseProperty("UserAvatar")]
[InverseProperty(nameof(DriveFile.UserAvatar))]
public virtual DriveFile? Avatar { get; set; }
[ForeignKey("BannerId")]
[InverseProperty("UserBanner")]
[InverseProperty(nameof(DriveFile.UserBanner))]
public virtual DriveFile? Banner { get; set; }
[InverseProperty("Blockee")]
[InverseProperty(nameof(Blocking.Blockee))]
public virtual ICollection<Blocking> BlockingBlockees { get; set; } = new List<Blocking>();
[InverseProperty("Blocker")]
[InverseProperty(nameof(Blocking.Blocker))]
public virtual ICollection<Blocking> BlockingBlockers { get; set; } = new List<Blocking>();
[InverseProperty("Follower")]
[InverseProperty(nameof(ChannelFollowing.Follower))]
public virtual ICollection<ChannelFollowing> ChannelFollowings { get; set; } = new List<ChannelFollowing>();
[InverseProperty("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("User")] public virtual ICollection<Clip> Clips { get; set; } = new List<Clip>();
[InverseProperty(nameof(Clip.User))] public virtual ICollection<Clip> Clips { get; set; } = new List<Clip>();
[InverseProperty("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("User")]
[InverseProperty(nameof(DriveFolder.User))]
public virtual ICollection<DriveFolder> DriveFolders { get; set; } = new List<DriveFolder>();
[InverseProperty("Followee")]
public virtual ICollection<FollowRequest> FollowRequestFollowees { get; set; } = new List<FollowRequest>();
[InverseProperty(nameof(FollowRequest.Followee))]
public virtual ICollection<FollowRequest> IncomingFollowRequests { get; set; } = new List<FollowRequest>();
[InverseProperty("Follower")]
public virtual ICollection<FollowRequest> FollowRequestFollowers { get; set; } = new List<FollowRequest>();
[InverseProperty(nameof(FollowRequest.Follower))]
public virtual ICollection<FollowRequest> OutgoingFollowRequests { get; set; } = new List<FollowRequest>();
[InverseProperty("Followee")]
public virtual ICollection<Following> FollowingFollowees { get; set; } = new List<Following>();
[InverseProperty(nameof(Tables.Following.Followee))]
public virtual ICollection<Following> IncomingFollowRelationships { get; set; } = new List<Following>();
[InverseProperty("Follower")]
public virtual ICollection<Following> FollowingFollowers { get; set; } = new List<Following>();
[InverseProperty(nameof(Tables.Following.Follower))]
public virtual ICollection<Following> OutgoingFollowRelationships { get; set; } = new List<Following>();
[InverseProperty("User")]
[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);
[InverseProperty(nameof(GalleryLike.User))]
public virtual ICollection<GalleryLike> GalleryLikes { get; set; } = new List<GalleryLike>();
[InverseProperty("User")]
[InverseProperty(nameof(GalleryPost.User))]
public virtual ICollection<GalleryPost> GalleryPosts { get; set; } = new List<GalleryPost>();
[InverseProperty("User")] public virtual HtmlUserCacheEntry? HtmlUserCacheEntry { get; set; }
[InverseProperty(nameof(Tables.HtmlUserCacheEntry.User))] public virtual HtmlUserCacheEntry? HtmlUserCacheEntry { get; set; }
[InverseProperty("Recipient")]
[InverseProperty(nameof(MessagingMessage.Recipient))]
public virtual ICollection<MessagingMessage> MessagingMessageRecipients { get; set; } =
new List<MessagingMessage>();
[InverseProperty("User")]
[InverseProperty(nameof(MessagingMessage.User))]
public virtual ICollection<MessagingMessage> MessagingMessageUsers { get; set; } = new List<MessagingMessage>();
[InverseProperty("User")]
[InverseProperty(nameof(ModerationLog.User))]
public virtual ICollection<ModerationLog> ModerationLogs { get; set; } = new List<ModerationLog>();
[InverseProperty("Mutee")] public virtual ICollection<Muting> MutingMutees { get; set; } = new List<Muting>();
[InverseProperty(nameof(Muting.Mutee))] public virtual ICollection<Muting> MutingMutees { get; set; } = new List<Muting>();
[InverseProperty("Muter")] public virtual ICollection<Muting> MutingMuters { get; set; } = new List<Muting>();
[InverseProperty(nameof(Muting.Muter))] public virtual ICollection<Muting> MutingMuters { get; set; } = new List<Muting>();
[InverseProperty("User")]
[InverseProperty(nameof(NoteFavorite.User))]
public virtual ICollection<NoteFavorite> NoteFavorites { get; set; } = new List<NoteFavorite>();
[InverseProperty("User")]
[InverseProperty(nameof(NoteReaction.User))]
public virtual ICollection<NoteReaction> NoteReactions { get; set; } = new List<NoteReaction>();
[InverseProperty("User")]
[InverseProperty(nameof(NoteThreadMuting.User))]
public virtual ICollection<NoteThreadMuting> NoteThreadMutings { get; set; } = new List<NoteThreadMuting>();
[InverseProperty("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("User")]
[InverseProperty(nameof(NoteWatching.User))]
public virtual ICollection<NoteWatching> NoteWatchings { get; set; } = new List<NoteWatching>();
[InverseProperty("User")] public virtual ICollection<Note> Notes { get; set; } = new List<Note>();
[InverseProperty(nameof(Note.User))] public virtual ICollection<Note> Notes { get; set; } = new List<Note>();
[InverseProperty("Notifiee")]
[InverseProperty(nameof(Notification.Notifiee))]
public virtual ICollection<Notification> NotificationNotifiees { get; set; } = new List<Notification>();
[InverseProperty("Notifier")]
[InverseProperty(nameof(Notification.Notifier))]
public virtual ICollection<Notification> NotificationNotifiers { get; set; } = new List<Notification>();
[InverseProperty("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("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("User")] public virtual ICollection<Page> Pages { get; set; } = new List<Page>();
[InverseProperty(nameof(Page.User))] public virtual ICollection<Page> Pages { get; set; } = new List<Page>();
[InverseProperty("User")]
[InverseProperty(nameof(PasswordResetRequest.User))]
public virtual ICollection<PasswordResetRequest> PasswordResetRequests { get; set; } =
new List<PasswordResetRequest>();
[InverseProperty("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("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("User")]
[InverseProperty(nameof(RegistryItem.User))]
public virtual ICollection<RegistryItem> RegistryItems { get; set; } = new List<RegistryItem>();
[InverseProperty("Mutee")]
[InverseProperty(nameof(RenoteMuting.Mutee))]
public virtual ICollection<RenoteMuting> RenoteMutingMutees { get; set; } = new List<RenoteMuting>();
[InverseProperty("Muter")]
[InverseProperty(nameof(RenoteMuting.Muter))]
public virtual ICollection<RenoteMuting> RenoteMutingMuters { get; set; } = new List<RenoteMuting>();
[InverseProperty("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("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("User")]
[InverseProperty(nameof(SwSubscription.User))]
public virtual ICollection<SwSubscription> SwSubscriptions { get; set; } = new List<SwSubscription>();
[InverseProperty("User")]
[InverseProperty(nameof(UserGroupInvitation.User))]
public virtual ICollection<UserGroupInvitation> UserGroupInvitations { get; set; } =
new List<UserGroupInvitation>();
[InverseProperty("User")]
[InverseProperty(nameof(UserGroupMember.User))]
public virtual ICollection<UserGroupMember> UserGroupMemberships { get; set; } = new List<UserGroupMember>();
[InverseProperty("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("User")] public virtual UserKeypair? UserKeypair { get; set; }
[InverseProperty(nameof(Tables.UserKeypair.User))] public virtual UserKeypair? UserKeypair { get; set; }
[InverseProperty("User")]
[InverseProperty(nameof(UserListMember.User))]
public virtual ICollection<UserListMember> UserListMembers { get; set; } = new List<UserListMember>();
[InverseProperty("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("User")]
[InverseProperty(nameof(UserNotePin.User))]
public virtual ICollection<UserNotePin> UserNotePins { get; set; } = new List<UserNotePin>();
[InverseProperty("User")] public virtual UserProfile? UserProfile { get; set; }
[InverseProperty(nameof(Tables.UserProfile.User))] public virtual UserProfile? UserProfile { get; set; }
[InverseProperty("User")] public virtual UserPublickey? UserPublickey { get; set; }
[InverseProperty(nameof(Tables.UserPublickey.User))] public virtual UserPublickey? UserPublickey { get; set; }
[InverseProperty("User")]
[InverseProperty(nameof(UserSecurityKey.User))]
public virtual ICollection<UserSecurityKey> UserSecurityKeys { get; set; } = new List<UserSecurityKey>();
[InverseProperty("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>();
}

View file

@ -30,17 +30,17 @@ public class UserGroup {
[Column("isPrivate")] public bool IsPrivate { get; set; }
[InverseProperty("Group")]
[InverseProperty(nameof(MessagingMessage.Group))]
public virtual ICollection<MessagingMessage> MessagingMessages { get; set; } = new List<MessagingMessage>();
[ForeignKey("UserId")]
[InverseProperty("UserGroups")]
[InverseProperty(nameof(Tables.User.UserGroups))]
public virtual User User { get; set; } = null!;
[InverseProperty("UserGroup")]
[InverseProperty(nameof(UserGroupInvitation.UserGroup))]
public virtual ICollection<UserGroupInvitation> UserGroupInvitations { get; set; } =
new List<UserGroupInvitation>();
[InverseProperty("UserGroup")]
[InverseProperty(nameof(UserGroupMember.UserGroup))]
public virtual ICollection<UserGroupMember> UserGroupMembers { get; set; } = new List<UserGroupMember>();
}

View file

@ -34,14 +34,14 @@ public class UserGroupInvitation {
[StringLength(32)]
public string UserGroupId { get; set; } = null!;
[InverseProperty("UserGroupInvitation")]
[InverseProperty(nameof(Notification.UserGroupInvitation))]
public virtual ICollection<Notification> Notifications { get; set; } = new List<Notification>();
[ForeignKey("UserId")]
[InverseProperty("UserGroupInvitations")]
[InverseProperty(nameof(Tables.User.UserGroupInvitations))]
public virtual User User { get; set; } = null!;
[ForeignKey("UserGroupId")]
[InverseProperty("UserGroupInvitations")]
[InverseProperty(nameof(Tables.UserGroup.UserGroupInvitations))]
public virtual UserGroup UserGroup { get; set; } = null!;
}

View file

@ -34,14 +34,14 @@ public class UserGroupMember {
[StringLength(32)]
public string UserGroupId { get; set; } = null!;
[InverseProperty("UserGroupMember")]
[InverseProperty(nameof(Antenna.UserGroupMember))]
public virtual ICollection<Antenna> Antennas { get; set; } = new List<Antenna>();
[ForeignKey("UserId")]
[InverseProperty("UserGroupMemberships")]
[InverseProperty(nameof(Tables.User.UserGroupMemberships))]
public virtual User User { get; set; } = null!;
[ForeignKey("UserGroupId")]
[InverseProperty("UserGroupMembers")]
[InverseProperty(nameof(Tables.UserGroup.UserGroupMembers))]
public virtual UserGroup UserGroup { get; set; } = null!;
}

View file

@ -19,6 +19,6 @@ public class UserKeypair {
public string PrivateKey { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("UserKeypair")]
[InverseProperty(nameof(Tables.User.UserKeypair))]
public virtual User User { get; set; } = null!;
}

View file

@ -38,12 +38,12 @@ public class UserList {
[Column("hideFromHomeTl")]
public bool HideFromHomeTl { get; set; }
[InverseProperty("UserList")] public virtual ICollection<Antenna> Antennas { get; set; } = new List<Antenna>();
[InverseProperty(nameof(Antenna.UserList))] public virtual ICollection<Antenna> Antennas { get; set; } = new List<Antenna>();
[ForeignKey("UserId")]
[InverseProperty("UserLists")]
[InverseProperty(nameof(Tables.User.UserLists))]
public virtual User User { get; set; } = null!;
[InverseProperty("UserList")]
[InverseProperty(nameof(UserListMember.UserList))]
public virtual ICollection<UserListMember> UserListMembers { get; set; } = new List<UserListMember>();
}

View file

@ -35,10 +35,10 @@ public class UserListMember {
public string UserListId { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("UserListMembers")]
[InverseProperty(nameof(Tables.User.UserListMembers))]
public virtual User User { get; set; } = null!;
[ForeignKey("UserListId")]
[InverseProperty("UserListMembers")]
[InverseProperty(nameof(Tables.UserList.UserListMembers))]
public virtual UserList UserList { get; set; } = null!;
}

View file

@ -24,10 +24,10 @@ public class UserNotePin {
[Column("noteId")] [StringLength(32)] public string NoteId { get; set; } = null!;
[ForeignKey("NoteId")]
[InverseProperty("UserNotePins")]
[InverseProperty(nameof(Tables.Note.UserNotePins))]
public virtual Note Note { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("UserNotePins")]
[InverseProperty(nameof(Tables.User.UserNotePins))]
public virtual User User { get; set; } = null!;
}

View file

@ -155,11 +155,11 @@ public class UserProfile {
public string Mentions { get; set; } = null!;
[ForeignKey("PinnedPageId")]
[InverseProperty("UserProfile")]
[InverseProperty(nameof(Page.UserProfile))]
public virtual Page? PinnedPage { get; set; }
[ForeignKey("UserId")]
[InverseProperty("UserProfile")]
[InverseProperty(nameof(Tables.User.UserProfile))]
public virtual User User { get; set; } = null!;
[PgName("user_profile_ffvisibility_enum")]

View file

@ -19,6 +19,6 @@ public class UserPublickey {
public string KeyPem { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("UserPublickey")]
[InverseProperty(nameof(Tables.User.UserPublickey))]
public virtual User User { get; set; } = null!;
}

View file

@ -37,6 +37,6 @@ public class UserSecurityKey {
public string Name { get; set; } = null!;
[ForeignKey("UserId")]
[InverseProperty("UserSecurityKeys")]
[InverseProperty(nameof(Tables.User.UserSecurityKeys))]
public virtual User User { get; set; } = null!;
}

View file

@ -50,6 +50,6 @@ public class Webhook {
[Column("latestStatus")] public int? LatestStatus { get; set; }
[ForeignKey("UserId")]
[InverseProperty("Webhooks")]
[InverseProperty(nameof(Tables.User.Webhooks))]
public virtual User User { get; set; } = null!;
}

View file

@ -1,16 +1,7 @@
using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
using Iceshrimp.Backend.Core.Database.Tables;
namespace Iceshrimp.Backend.Core.Extensions;
public static class EnumerableExtensions {
public static async Task<IEnumerable<T>> AwaitAllAsync<T>(this IEnumerable<Task<T>> tasks) {
return await Task.WhenAll(tasks);
}
public static async Task<IEnumerable<Status>> RenderAllForMastodonAsync(
this IEnumerable<Note> notes, NoteRenderer renderer) {
return await notes.Select(async p => await renderer.RenderAsync(p)).AwaitAllAsync();
}
}

View file

@ -1,9 +1,11 @@
using Iceshrimp.Backend.Controllers.Mastodon.Renderers;
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
using Iceshrimp.Backend.Core.Database.Tables;
using Microsoft.EntityFrameworkCore;
namespace Iceshrimp.Backend.Core.Helpers;
namespace Iceshrimp.Backend.Core.Extensions;
public static class QueryHelpers {
public static class NoteQueryableExtensions {
public static IQueryable<Note> WithIncludes(this IQueryable<Note> query) {
return query.Include(p => p.User)
.Include(p => p.Renote)
@ -16,11 +18,17 @@ public static class QueryHelpers {
return query.Where(note => note.Visibility == visibility);
}
public static IQueryable<Note> IsFollowedBy(this IQueryable<Note> query, User user) {
return query.Where(note => note.User.FollowingFollowees.Any(following => following.Follower == user));
public static IQueryable<Note> FilterByFollowingAndOwn(this IQueryable<Note> query, User user) {
return query.Where(note => note.User == user || note.User.IsFollowedBy(user));
}
public static IQueryable<Note> OrderByIdDesc(this IQueryable<Note> query) {
return query.OrderByDescending(note => note.Id);
}
public static async Task<IEnumerable<Status>> RenderAllForMastodonAsync(
this IQueryable<Note> notes, NoteRenderer renderer) {
var list = await notes.ToListAsync();
return await list.Select(renderer.RenderAsync).AwaitAllAsync();
}
}

View file

@ -18,6 +18,7 @@
<PackageReference Include="Asp.Versioning.Http" Version="8.0.0"/>
<PackageReference Include="cuid.net" Version="5.0.2"/>
<PackageReference Include="dotNetRdf.Core" Version="3.2.1-dev"/>
<PackageReference Include="EntityFrameworkCore.Projectables" Version="3.0.4" />
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0"/>
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.1"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0"/>