From 6aa6833163ce3e7665a65ee2642d69d2f4c670a3 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Tue, 30 Dec 2025 23:37:57 +0800 Subject: [PATCH] :recycle: Refactor activitypub content storage --- .../Models/CloudFileReferenceObject.cs | 20 +- .../Models/FediverseActivity.cs | 78 - DysonNetwork.Shared/Models/FediverseActor.cs | 2 - .../Models/FediverseContent.cs | 143 - .../Models/FediverseInstance.cs | 1 - .../Models/FediverseReaction.cs | 40 - DysonNetwork.Shared/Models/Post.cs | 152 +- DysonNetwork.Shared/Proto/file.proto | 9 + DysonNetwork.Shared/Proto/post.proto | 40 +- .../ActivityPubActivityProcessor.cs | 163 +- DysonNetwork.Sphere/AppDatabase.cs | 36 - .../20251228100758_AddActivityPub.Designer.cs | 24 +- .../20251228100758_AddActivityPub.cs | 8 +- ...1228165042_AddSeprateActorType.Designer.cs | 24 +- ...173217_EnrichFediverseInstance.Designer.cs | 24 +- ...0251229163103_BetterLocalActor.Designer.cs | 24 +- ...0251229174336_AddPublisherKeys.Designer.cs | 24 +- ...153545_MergeFediverseDataClass.Designer.cs | 2385 +++++++++++++++++ .../20251230153545_MergeFediverseDataClass.cs | 433 +++ .../Migrations/AppDatabaseModelSnapshot.cs | 458 +--- .../Post/PostActionController.cs | 76 +- DysonNetwork.Sphere/Post/PostController.cs | 4 +- DysonNetwork.Sphere/Post/PostService.cs | 68 +- .../Publisher/PublisherService.cs | 7 +- .../Rewind/SphereRewindServiceGrpc.cs | 13 +- .../Timeline/TimelineService.cs | 2 +- 26 files changed, 3339 insertions(+), 919 deletions(-) delete mode 100644 DysonNetwork.Shared/Models/FediverseActivity.cs delete mode 100644 DysonNetwork.Shared/Models/FediverseContent.cs delete mode 100644 DysonNetwork.Shared/Models/FediverseReaction.cs create mode 100644 DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.Designer.cs create mode 100644 DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.cs diff --git a/DysonNetwork.Shared/Models/CloudFileReferenceObject.cs b/DysonNetwork.Shared/Models/CloudFileReferenceObject.cs index dad0421..cdeebbb 100644 --- a/DysonNetwork.Shared/Models/CloudFileReferenceObject.cs +++ b/DysonNetwork.Shared/Models/CloudFileReferenceObject.cs @@ -1,3 +1,4 @@ +using System.ComponentModel.DataAnnotations; using DysonNetwork.Shared.Proto; namespace DysonNetwork.Shared.Models; @@ -22,6 +23,7 @@ public enum ContentSensitiveMark /// /// The class that used in jsonb columns which referenced the cloud file. /// The aim of this class is to store some properties that won't change to a file to reduce the database load. +/// Supports both local cloud files (with Id) and external/fediverse files (with Url). /// public class SnCloudFileReferenceObject : ModelBase, ICloudFile { @@ -34,6 +36,11 @@ public class SnCloudFileReferenceObject : ModelBase, ICloudFile public string? Hash { get; set; } public long Size { get; set; } public bool HasCompression { get; set; } = false; + + [MaxLength(2048)] public string? Url { get; set; } + public int? Width { get; set; } + public int? Height { get; set; } + [MaxLength(64)] public string? Blurhash { get; set; } public static SnCloudFileReferenceObject FromProtoValue(Proto.CloudFile proto) { @@ -49,7 +56,11 @@ public class SnCloudFileReferenceObject : ModelBase, ICloudFile MimeType = proto.MimeType, Hash = proto.Hash, Size = proto.Size, - HasCompression = proto.HasCompression + HasCompression = proto.HasCompression, + Url = string.IsNullOrEmpty(proto.Url) ? null : proto.Url, + Width = proto.HasWidth ? proto.Width : null, + Height = proto.HasHeight ? proto.Height : null, + Blurhash = proto.HasBlurhash ? proto.Blurhash : null }; } @@ -67,10 +78,11 @@ public class SnCloudFileReferenceObject : ModelBase, ICloudFile Size = Size, HasCompression = HasCompression, ContentType = MimeType ?? string.Empty, - Url = string.Empty, - // Convert file metadata + Url = Url ?? string.Empty, + Width = Width ?? 0, + Height = Height ?? 0, + Blurhash = Blurhash ?? string.Empty, FileMeta = GrpcTypeHelper.ConvertObjectToByteString(FileMeta), - // Convert user metadata UserMeta = GrpcTypeHelper.ConvertObjectToByteString(UserMeta), SensitiveMarks = GrpcTypeHelper.ConvertObjectToByteString(SensitiveMarks) }; diff --git a/DysonNetwork.Shared/Models/FediverseActivity.cs b/DysonNetwork.Shared/Models/FediverseActivity.cs deleted file mode 100644 index d1b53c7..0000000 --- a/DysonNetwork.Shared/Models/FediverseActivity.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text.Json.Serialization; -using Microsoft.EntityFrameworkCore; -using NodaTime; - -namespace DysonNetwork.Shared.Models; - -public class SnFediverseActivity : ModelBase -{ - public Guid Id { get; set; } = Guid.NewGuid(); - - [MaxLength(2048)] - public string Uri { get; set; } = null!; - - public FediverseActivityType Type { get; set; } - - [MaxLength(2048)] - public string? ObjectUri { get; set; } - - [MaxLength(2048)] - public string? TargetUri { get; set; } - - public Instant? PublishedAt { get; set; } - - public bool IsLocal { get; set; } - - [Column(TypeName = "jsonb")] - public Dictionary? RawData { get; set; } - - public Guid ActorId { get; set; } - [JsonIgnore] - public SnFediverseActor Actor { get; set; } = null!; - - public Guid? ContentId { get; set; } - [JsonIgnore] - public SnFediverseContent? Content { get; set; } - - public Guid? TargetActorId { get; set; } - [JsonIgnore] - public SnFediverseActor? TargetActor { get; set; } - - public Guid? LocalPostId { get; set; } - public Guid? LocalAccountId { get; set; } - - public ActivityStatus Status { get; set; } = ActivityStatus.Pending; - - [MaxLength(4096)] - public string? ErrorMessage { get; set; } -} - -public enum FediverseActivityType -{ - Create, - Update, - Delete, - Follow, - Unfollow, - Like, - Announce, - Undo, - Accept, - Reject, - Add, - Remove, - Block, - Unblock, - Flag, - Move -} - -public enum ActivityStatus -{ - Pending, - Processing, - Completed, - Failed -} diff --git a/DysonNetwork.Shared/Models/FediverseActor.cs b/DysonNetwork.Shared/Models/FediverseActor.cs index 3d33ac5..c734a60 100644 --- a/DysonNetwork.Shared/Models/FediverseActor.cs +++ b/DysonNetwork.Shared/Models/FediverseActor.cs @@ -34,8 +34,6 @@ public class SnFediverseActor : ModelBase public Guid InstanceId { get; set; } public SnFediverseInstance Instance { get; set; } = null!; - [JsonIgnore] public ICollection Contents { get; set; } = []; - [JsonIgnore] public ICollection Activities { get; set; } = []; [JsonIgnore] public ICollection FollowingRelationships { get; set; } = []; [JsonIgnore] public ICollection FollowerRelationships { get; set; } = []; diff --git a/DysonNetwork.Shared/Models/FediverseContent.cs b/DysonNetwork.Shared/Models/FediverseContent.cs deleted file mode 100644 index 61585a8..0000000 --- a/DysonNetwork.Shared/Models/FediverseContent.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text.Json.Serialization; -using Microsoft.EntityFrameworkCore; -using NodaTime; - -namespace DysonNetwork.Shared.Models; - -[Index(nameof(Uri), IsUnique = true)] -public class SnFediverseContent : ModelBase -{ - public Guid Id { get; set; } = Guid.NewGuid(); - - [MaxLength(2048)] - public string Uri { get; set; } = null!; - - public FediverseContentType Type { get; set; } - - [MaxLength(1024)] - public string? Title { get; set; } - - [MaxLength(4096)] - public string? Summary { get; set; } - - public string? Content { get; set; } - - public string? ContentHtml { get; set; } - - [MaxLength(2048)] - public string? Language { get; set; } - - [MaxLength(2048)] - public string? InReplyTo { get; set; } - - [MaxLength(2048)] - public string? AnnouncedContentUri { get; set; } - - public Instant? PublishedAt { get; set; } - public Instant? EditedAt { get; set; } - - public bool IsSensitive { get; set; } = false; - - [Column(TypeName = "jsonb")] - public List? Attachments { get; set; } - - [Column(TypeName = "jsonb")] - public List? Mentions { get; set; } - - [Column(TypeName = "jsonb")] - public List? Tags { get; set; } - - [Column(TypeName = "jsonb")] - public List? Emojis { get; set; } - - [Column(TypeName = "jsonb")] - public Dictionary? Metadata { get; set; } - - public Guid ActorId { get; set; } - [JsonIgnore] - public SnFediverseActor Actor { get; set; } = null!; - - public Guid InstanceId { get; set; } - [JsonIgnore] - public SnFediverseInstance Instance { get; set; } = null!; - - [JsonIgnore] - public ICollection Activities { get; set; } = []; - - [JsonIgnore] - public ICollection Reactions { get; set; } = []; - - public int ReplyCount { get; set; } - public int BoostCount { get; set; } - public int LikeCount { get; set; } - - public Guid? LocalPostId { get; set; } - [NotMapped] - public SnPost? LocalPost { get; set; } -} - -public enum FediverseContentType -{ - Note, - Article, - Image, - Video, - Audio, - Page, - Question, - Event, - Document -} - -public class ContentAttachment -{ - [MaxLength(2048)] - public string? Url { get; set; } - - [MaxLength(2048)] - public string? MediaType { get; set; } - - [MaxLength(1024)] - public string? Name { get; set; } - - public int? Width { get; set; } - public int? Height { get; set; } - - [MaxLength(64)] - public string? Blurhash { get; set; } -} - -public class ContentMention -{ - [MaxLength(256)] - public string? Username { get; set; } - - [MaxLength(2048)] - public string? Url { get; set; } - - [MaxLength(2048)] - public string? ActorUri { get; set; } -} - -public class ContentTag -{ - [MaxLength(256)] - public string? Name { get; set; } - - [MaxLength(2048)] - public string? Url { get; set; } -} - -public class ContentEmoji -{ - [MaxLength(64)] - public string? Shortcode { get; set; } - - [MaxLength(2048)] - public string? StaticUrl { get; set; } - - [MaxLength(2048)] - public string? Url { get; set; } -} diff --git a/DysonNetwork.Shared/Models/FediverseInstance.cs b/DysonNetwork.Shared/Models/FediverseInstance.cs index 0edb8d6..8458ff9 100644 --- a/DysonNetwork.Shared/Models/FediverseInstance.cs +++ b/DysonNetwork.Shared/Models/FediverseInstance.cs @@ -28,7 +28,6 @@ public class SnFediverseInstance : ModelBase [MaxLength(2048)] public string? BlockReason { get; set; } [JsonIgnore] public ICollection Actors { get; set; } = []; - [JsonIgnore] public ICollection Contents { get; set; } = []; public Instant? LastFetchedAt { get; set; } public Instant? LastActivityAt { get; set; } diff --git a/DysonNetwork.Shared/Models/FediverseReaction.cs b/DysonNetwork.Shared/Models/FediverseReaction.cs deleted file mode 100644 index 09a5323..0000000 --- a/DysonNetwork.Shared/Models/FediverseReaction.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text.Json.Serialization; -using Microsoft.EntityFrameworkCore; -using NodaTime; - -namespace DysonNetwork.Shared.Models; - -public class SnFediverseReaction : ModelBase -{ - public Guid Id { get; set; } = Guid.NewGuid(); - - [MaxLength(2048)] - public string Uri { get; set; } = null!; - - public FediverseReactionType Type { get; set; } - - [MaxLength(64)] - public string? Emoji { get; set; } - - public bool IsLocal { get; set; } - - public Guid ContentId { get; set; } - [JsonIgnore] - public SnFediverseContent Content { get; set; } = null!; - - public Guid ActorId { get; set; } - [JsonIgnore] - public SnFediverseActor Actor { get; set; } = null!; - - public Guid? LocalAccountId { get; set; } - public Guid? LocalReactionId { get; set; } -} - -public enum FediverseReactionType -{ - Like, - Emoji, - Dislike -} diff --git a/DysonNetwork.Shared/Models/Post.cs b/DysonNetwork.Shared/Models/Post.cs index f0bae12..8f46bdc 100644 --- a/DysonNetwork.Shared/Models/Post.cs +++ b/DysonNetwork.Shared/Models/Post.cs @@ -21,6 +21,12 @@ public enum PostVisibility Private, } +public enum PostContentType +{ + Markdown, + Html, +} + public enum PostPinMode { PublisherPage, @@ -28,6 +34,39 @@ public enum PostPinMode ReplyPage, } +public class ContentMention +{ + [MaxLength(256)] + public string? Username { get; set; } + + [MaxLength(2048)] + public string? Url { get; set; } + + [MaxLength(2048)] + public string? ActorUri { get; set; } +} + +public class ContentTag +{ + [MaxLength(256)] + public string? Name { get; set; } + + [MaxLength(2048)] + public string? Url { get; set; } +} + +public class ContentEmoji +{ + [MaxLength(64)] + public string? Shortcode { get; set; } + + [MaxLength(2048)] + public string? StaticUrl { get; set; } + + [MaxLength(2048)] + public string? Url { get; set; } +} + public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent { public Guid Id { get; set; } @@ -47,11 +86,13 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent // ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength public string? Content { get; set; } + public PostContentType ContentType { get; set; } = PostContentType.Markdown; + public PostType Type { get; set; } public PostPinMode? PinMode { get; set; } [Column(TypeName = "jsonb")] - public Dictionary? Meta { get; set; } + public Dictionary? Metadata { get; set; } [Column(TypeName = "jsonb")] public List? SensitiveMarks { get; set; } = []; @@ -59,17 +100,28 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent [Column(TypeName = "jsonb")] public PostEmbedView? EmbedView { get; set; } + [MaxLength(8192)] public string? FediverseUri { get; set; } + public FediverseContentType? FediverseType { get; set; } + [MaxLength(2048)] public string? Language { get; set; } + [Column(TypeName = "jsonb")] + public List? Mentions { get; set; } + + public int BoostCount { get; set; } + public int LikeCount { get; set; } + + public Guid? ActorId { get; set; } + public SnFediverseActor? Actor { get; set; } + public int ViewsUnique { get; set; } public int ViewsTotal { get; set; } public int Upvotes { get; set; } public int Downvotes { get; set; } public decimal AwardedScore { get; set; } - [NotMapped] - public Dictionary ReactionsCount { get; set; } = new(); + public int RepliesCount { get; set; } [NotMapped] - public int RepliesCount { get; set; } + public Dictionary ReactionsCount { get; set; } = new(); [NotMapped] public Dictionary? ReactionsMade { get; set; } @@ -90,8 +142,8 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent [Column(TypeName = "jsonb")] public List Attachments { get; set; } = []; - public Guid PublisherId { get; set; } - public SnPublisher Publisher { get; set; } = null!; + public Guid? PublisherId { get; set; } + public SnPublisher? Publisher { get; set; } public List Awards { get; set; } = []; @@ -133,7 +185,7 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent RepliedGone = RepliedGone, ForwardedGone = ForwardedGone, PublisherId = PublisherId.ToString(), - Publisher = Publisher.ToProtoValue(), + Publisher = Publisher?.ToProtoValue(), CreatedAt = Timestamp.FromDateTimeOffset(CreatedAt.ToDateTimeOffset()), UpdatedAt = Timestamp.FromDateTimeOffset(UpdatedAt.ToDateTimeOffset()), }; @@ -147,11 +199,13 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent if (Content != null) proto.Content = Content; + proto.ContentType = (Proto.PostContentType)((int)ContentType + 1); + if (PinMode.HasValue) proto.PinMode = (Proto.PostPinMode)((int)PinMode.Value + 1); - if (Meta != null) - proto.Meta = GrpcTypeHelper.ConvertObjectToByteString(Meta); + if (Metadata != null) + proto.Meta = GrpcTypeHelper.ConvertObjectToByteString(Metadata); if (SensitiveMarks != null) proto.SensitiveMarks = GrpcTypeHelper.ConvertObjectToByteString(SensitiveMarks); @@ -159,6 +213,30 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent if (EmbedView != null) proto.EmbedView = EmbedView.ToProtoValue(); + if (!string.IsNullOrEmpty(FediverseUri)) + proto.FediverseUri = FediverseUri; + + if (FediverseType.HasValue) + proto.FediverseType = (Proto.FediverseContentType)((int)FediverseType.Value + 1); + + if (!string.IsNullOrEmpty(Language)) + proto.Language = Language; + + if (Mentions != null) + proto.Mentions.AddRange(Mentions.Select(m => new Proto.ContentMention + { + Username = m.Username, + Url = m.Url, + ActorUri = m.ActorUri + })); + + proto.RepliesCount = RepliesCount; + proto.BoostCount = BoostCount; + proto.LikeCount = LikeCount; + + if (ActorId.HasValue) + proto.ActorId = ActorId.Value.ToString(); + if (RepliedPostId.HasValue) { proto.RepliedPostId = RepliedPostId.Value.ToString(); @@ -220,7 +298,7 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent RepliedGone = proto.RepliedGone, ForwardedGone = proto.ForwardedGone, PublisherId = Guid.Parse(proto.PublisherId), - Publisher = SnPublisher.FromProtoValue(proto.Publisher), + Publisher = proto.Publisher != null ? SnPublisher.FromProtoValue(proto.Publisher) : null, CreatedAt = Instant.FromDateTimeOffset(proto.CreatedAt.ToDateTimeOffset()), UpdatedAt = Instant.FromDateTimeOffset(proto.UpdatedAt.ToDateTimeOffset()), }; @@ -234,11 +312,13 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent if (!string.IsNullOrEmpty(proto.Content)) post.Content = proto.Content; + post.ContentType = (PostContentType)((int)proto.ContentType - 1); + if (proto is { HasPinMode: true, PinMode: > 0 }) post.PinMode = (PostPinMode)(proto.PinMode - 1); if (proto.Meta != null) - post.Meta = GrpcTypeHelper.ConvertByteStringToObject>( + post.Metadata = GrpcTypeHelper.ConvertByteStringToObject>( proto.Meta ); @@ -250,6 +330,30 @@ public class SnPost : ModelBase, IIdentifiedResource, ITimelineEvent if (proto.EmbedView is not null) post.EmbedView = PostEmbedView.FromProtoValue(proto.EmbedView); + if (!string.IsNullOrEmpty(proto.FediverseUri)) + post.FediverseUri = proto.FediverseUri; + + if (proto.HasFediverseType && proto.FediverseType > 0) + post.FediverseType = (FediverseContentType)((int)proto.FediverseType - 1); + + if (!string.IsNullOrEmpty(proto.Language)) + post.Language = proto.Language; + + if (proto.Mentions != null && proto.Mentions.Count > 0) + post.Mentions = proto.Mentions.Select(m => new ContentMention + { + Username = m.Username, + Url = m.Url, + ActorUri = m.ActorUri + }).ToList(); + + post.RepliesCount = proto.RepliesCount; + post.BoostCount = proto.BoostCount; + post.LikeCount = proto.LikeCount; + + if (!string.IsNullOrEmpty(proto.ActorId)) + post.ActorId = Guid.Parse(proto.ActorId); + if (!string.IsNullOrEmpty(proto.RepliedPostId)) { post.RepliedPostId = Guid.Parse(proto.RepliedPostId); @@ -487,13 +591,17 @@ public class SnPostReaction : ModelBase public PostReactionAttitude Attitude { get; set; } public Guid PostId { get; set; } + [JsonIgnore] public SnPost Post { get; set; } = null!; + + public Guid? AccountId { get; set; } + [NotMapped] public SnAccount? Account { get; set; } - [JsonIgnore] - public SnPost Post { get; set; } = null!; - public Guid AccountId { get; set; } + [MaxLength(2048)] public string? FediverseUri { get; set; } - [NotMapped] - public SnAccount? Account { get; set; } + public Guid? ActorId { get; set; } + public SnFediverseActor? Actor { get; set; } + + public bool IsLocal { get; set; } = true; public PostReaction ToProtoValue() { @@ -503,7 +611,10 @@ public class SnPostReaction : ModelBase Symbol = Symbol, Attitude = (Proto.PostReactionAttitude)((int)Attitude + 1), PostId = PostId.ToString(), - AccountId = AccountId.ToString(), + AccountId = AccountId?.ToString() ?? string.Empty, + FediverseUri = FediverseUri ?? string.Empty, + IsLocal = IsLocal, + ActorId = ActorId?.ToString() ?? string.Empty, CreatedAt = Timestamp.FromDateTimeOffset(CreatedAt.ToDateTimeOffset()), UpdatedAt = Timestamp.FromDateTimeOffset(UpdatedAt.ToDateTimeOffset()), }; @@ -515,7 +626,7 @@ public class SnPostReaction : ModelBase return proto; } - public static SnPostReaction FromProtoValue(Proto.PostReaction proto) + public static SnPostReaction FromProtoValue(PostReaction proto) { return new SnPostReaction { @@ -523,8 +634,11 @@ public class SnPostReaction : ModelBase Symbol = proto.Symbol, Attitude = (PostReactionAttitude)((int)proto.Attitude - 1), PostId = Guid.Parse(proto.PostId), - AccountId = Guid.Parse(proto.AccountId), + AccountId = !string.IsNullOrEmpty(proto.AccountId) ? Guid.Parse(proto.AccountId) : null, Account = proto.Account != null ? SnAccount.FromProtoValue(proto.Account) : null, + FediverseUri = !string.IsNullOrEmpty(proto.FediverseUri) ? proto.FediverseUri : null, + ActorId = !string.IsNullOrEmpty(proto.ActorId) ? Guid.Parse(proto.ActorId) : null, + IsLocal = proto.IsLocal, CreatedAt = Instant.FromDateTimeOffset(proto.CreatedAt.ToDateTimeOffset()), UpdatedAt = Instant.FromDateTimeOffset(proto.UpdatedAt.ToDateTimeOffset()), }; diff --git a/DysonNetwork.Shared/Proto/file.proto b/DysonNetwork.Shared/Proto/file.proto index 2651850..c97f977 100644 --- a/DysonNetwork.Shared/Proto/file.proto +++ b/DysonNetwork.Shared/Proto/file.proto @@ -45,6 +45,15 @@ message CloudFile { // When the file was uploaded google.protobuf.Timestamp uploaded_at = 11; + + // Image/Video width (optional, for media files) + optional int32 width = 13; + + // Image/Video height (optional, for media files) + optional int32 height = 14; + + // Blurhash for placeholder (optional, for images) + optional string blurhash = 15; } // Service for file operations diff --git a/DysonNetwork.Shared/Proto/post.proto b/DysonNetwork.Shared/Proto/post.proto index a937b8d..60895c1 100644 --- a/DysonNetwork.Shared/Proto/post.proto +++ b/DysonNetwork.Shared/Proto/post.proto @@ -61,8 +61,33 @@ enum PostEmbedViewRenderer { WEBVIEW = 1; } +enum PostContentType { + POST_CONTENT_TYPE_UNSPECIFIED = 0; + MARKDOWN = 1; + HTML = 2; +} + +enum FediverseContentType { + FEDIVERSE_CONTENT_TYPE_UNSPECIFIED = 0; + FEDIVERSE_NOTE = 1; + FEDIVERSE_ARTICLE = 2; + FEDIVERSE_IMAGE = 3; + FEDIVERSE_VIDEO = 4; + FEDIVERSE_AUDIO = 5; + FEDIVERSE_PAGE = 6; + FEDIVERSE_QUESTION = 7; + FEDIVERSE_EVENT = 8; + FEDIVERSE_DOCUMENT = 9; +} + // Messages +message ContentMention { + optional string username = 1; + optional string url = 2; + optional string actor_uri = 3; +} + message PostEmbedView { string uri = 1; optional double aspect_ratio = 2; @@ -110,7 +135,16 @@ message Post { repeated CloudFile attachments = 30; // List string publisher_id = 31; - Publisher publisher = 32; + optional Publisher publisher = 32; + + optional string fediverse_uri = 41; + optional FediverseContentType fediverse_type = 42; + optional string language = 43; + optional PostContentType content_type = 44; + repeated ContentMention mentions = 48; + int32 boost_count = 50; + int32 like_count = 51; + optional string actor_id = 53; repeated PostAward awards = 33; repeated PostReaction reactions = 34; @@ -189,6 +223,10 @@ message PostReaction { string account_id = 5; optional Account account = 6; // optional full account + optional string fediverse_uri = 9; + optional string actor_id = 11; + bool is_local = 10; + google.protobuf.Timestamp created_at = 7; google.protobuf.Timestamp updated_at = 8; } diff --git a/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityProcessor.cs b/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityProcessor.cs index 3173afb..9364227 100644 --- a/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityProcessor.cs +++ b/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityProcessor.cs @@ -2,6 +2,12 @@ using DysonNetwork.Shared.Models; using Microsoft.EntityFrameworkCore; using NodaTime; using System.Text.Json; +using DysonNetwork.Shared.Proto; +using ContentMention = DysonNetwork.Shared.Models.ContentMention; +using PostContentType = DysonNetwork.Shared.Models.PostContentType; +using PostReactionAttitude = DysonNetwork.Shared.Models.PostReactionAttitude; +using PostType = DysonNetwork.Shared.Models.PostType; +using PostVisibility = DysonNetwork.Shared.Models.PostVisibility; namespace DysonNetwork.Sphere.ActivityPub; @@ -246,14 +252,13 @@ public class ActivityPubActivityProcessor( } var actor = await GetOrCreateActorAsync(actorUri); - var instance = await GetOrCreateInstanceAsync(actorUri); var contentUri = objectDict.GetValueOrDefault("id")?.ToString(); if (string.IsNullOrEmpty(contentUri)) return false; - var existingContent = await db.FediverseContents - .FirstOrDefaultAsync(c => c.Uri == contentUri); + var existingContent = await db.Posts + .FirstOrDefaultAsync(c => c.FediverseUri == contentUri); if (existingContent != null) { @@ -261,26 +266,28 @@ public class ActivityPubActivityProcessor( return true; } - var content = new SnFediverseContent + var content = new SnPost { - Uri = contentUri, - Type = objectType == "Article" ? FediverseContentType.Article : FediverseContentType.Note, + FediverseUri = contentUri, + FediverseType = objectType == "Article" ? FediverseContentType.FediverseArticle : FediverseContentType.FediverseNote, Title = objectDict.GetValueOrDefault("name")?.ToString(), - Summary = objectDict.GetValueOrDefault("summary")?.ToString(), + Description = objectDict.GetValueOrDefault("summary")?.ToString(), Content = objectDict.GetValueOrDefault("content")?.ToString(), - ContentHtml = objectDict.GetValueOrDefault("contentMap")?.ToString(), + ContentType = objectDict.GetValueOrDefault("contentMap") != null ? PostContentType.Html : PostContentType.Markdown, PublishedAt = ParseInstant(objectDict.GetValueOrDefault("published")), EditedAt = ParseInstant(objectDict.GetValueOrDefault("updated")), - IsSensitive = bool.TryParse(objectDict.GetValueOrDefault("sensitive")?.ToString(), out var sensitive) && sensitive, ActorId = actor.Id, - InstanceId = instance.Id, - Attachments = ParseAttachments(objectDict.GetValueOrDefault("attachment")), + Language = objectDict.GetValueOrDefault("language")?.ToString(), Mentions = ParseMentions(objectDict.GetValueOrDefault("tag")), - Tags = ParseTags(objectDict.GetValueOrDefault("tag")), - InReplyTo = objectDict.GetValueOrDefault("inReplyTo")?.ToString() + Attachments = ParseAttachments(objectDict.GetValueOrDefault("attachment")) ?? [], + Type = objectType == "Article" ? PostType.Article : PostType.Moment, + Visibility = PostVisibility.Public, + CreatedAt = SystemClock.Instance.GetCurrentInstant(), + UpdatedAt = SystemClock.Instance.GetCurrentInstant(), + Metadata = BuildMetadataFromActivity(objectDict) }; - db.FediverseContents.Add(content); + db.Posts.Add(content); await db.SaveChangesAsync(); logger.LogInformation("Created federated content: {Uri}", contentUri); @@ -294,8 +301,8 @@ public class ActivityPubActivityProcessor( return false; var actor = await GetOrCreateActorAsync(actorUri); - var content = await db.FediverseContents - .FirstOrDefaultAsync(c => c.Uri == objectUri); + var content = await db.Posts + .FirstOrDefaultAsync(c => c.FediverseUri == objectUri); if (content == null) { @@ -303,11 +310,11 @@ public class ActivityPubActivityProcessor( return false; } - var existingReaction = await db.FediverseReactions - .FirstOrDefaultAsync(r => - r.ActorId == actor.Id && - r.ContentId == content.Id && - r.Type == FediverseReactionType.Like); + var existingReaction = await db.PostReactions + .FirstOrDefaultAsync(r => + r.ActorId == actor.Id && + r.PostId == content.Id && + r.Symbol == "❤️"); if (existingReaction != null) { @@ -315,16 +322,20 @@ public class ActivityPubActivityProcessor( return true; } - var reaction = new SnFediverseReaction + var reaction = new SnPostReaction { - Uri = activity.GetValueOrDefault("id")?.ToString() ?? Guid.NewGuid().ToString(), - Type = FediverseReactionType.Like, + FediverseUri = activity.GetValueOrDefault("id")?.ToString() ?? Guid.NewGuid().ToString(), + Symbol = "❤️", + Attitude = PostReactionAttitude.Positive, IsLocal = false, - ContentId = content.Id, - ActorId = actor.Id + PostId = content.Id, + ActorId = actor.Id, + Actor = actor, + CreatedAt = SystemClock.Instance.GetCurrentInstant(), + UpdatedAt = SystemClock.Instance.GetCurrentInstant() }; - db.FediverseReactions.Add(reaction); + db.PostReactions.Add(reaction); content.LikeCount++; await db.SaveChangesAsync(); @@ -340,8 +351,8 @@ public class ActivityPubActivityProcessor( return false; var actor = await GetOrCreateActorAsync(actorUri); - var content = await db.FediverseContents - .FirstOrDefaultAsync(c => c.Uri == objectUri); + var content = await db.Posts + .FirstOrDefaultAsync(c => c.FediverseUri == objectUri); if (content != null) { @@ -359,8 +370,8 @@ public class ActivityPubActivityProcessor( if (string.IsNullOrEmpty(objectUri)) return false; - var content = await db.FediverseContents - .FirstOrDefaultAsync(c => c.Uri == objectUri); + var content = await db.Posts + .FirstOrDefaultAsync(c => c.FediverseUri == objectUri); if (content != null) { @@ -378,8 +389,8 @@ public class ActivityPubActivityProcessor( if (string.IsNullOrEmpty(objectUri)) return false; - var content = await db.FediverseContents - .FirstOrDefaultAsync(c => c.Uri == objectUri); + var content = await db.Posts + .FirstOrDefaultAsync(c => c.FediverseUri == objectUri); if (content != null) { @@ -416,18 +427,18 @@ public class ActivityPubActivityProcessor( { var actor = await GetOrCreateActorAsync(actorUri); - var reactions = await db.FediverseReactions - .Where(r => r.ActorId == actor.Id && r.Type == FediverseReactionType.Like) + var reactions = await db.PostReactions + .Where(r => r.ActorId == actor.Id && r.Symbol == "❤️") .ToListAsync(); foreach (var reaction in reactions) { - var content = await db.FediverseContents.FindAsync(reaction.ContentId); + var content = await db.Posts.FindAsync(reaction.PostId); if (content != null) { content.LikeCount--; } - db.FediverseReactions.Remove(reaction); + db.PostReactions.Remove(reaction); } await db.SaveChangesAsync(); @@ -436,8 +447,8 @@ public class ActivityPubActivityProcessor( private async Task UndoAnnounceAsync(string actorUri, string? activityId) { - var content = await db.FediverseContents - .FirstOrDefaultAsync(c => c.Uri == activityId); + var content = await db.Posts + .FirstOrDefaultAsync(c => c.FediverseUri == activityId); if (content != null) { @@ -518,32 +529,35 @@ public class ActivityPubActivityProcessor( return null; } - private List? ParseAttachments(object? value) + private static List? ParseAttachments(object? value) { - if (value == null) - return null; - - if (value is JsonElement element && element.ValueKind == JsonValueKind.Array) + if (value is JsonElement { ValueKind: JsonValueKind.Array } element) { return element.EnumerateArray() - .Select(attachment => new ContentAttachment + .Select(attachment => new SnCloudFileReferenceObject { + Id = Guid.NewGuid().ToString(), + Name = attachment.GetProperty("name").GetString() ?? string.Empty, Url = attachment.GetProperty("url").GetString(), - MediaType = attachment.GetProperty("mediaType").GetString(), - Name = attachment.GetProperty("name").GetString() + MimeType = attachment.GetProperty("mediaType").GetString(), + Width = attachment.GetProperty("width").GetInt32(), + Height = attachment.GetProperty("height").GetInt32(), + Blurhash = attachment.GetProperty("blurhash").GetString(), + FileMeta = new Dictionary(), + UserMeta = new Dictionary(), + Size = 0, + CreatedAt = SystemClock.Instance.GetCurrentInstant(), + UpdatedAt = SystemClock.Instance.GetCurrentInstant() }) .ToList(); } - + return null; } - private List? ParseMentions(object? value) + private static List? ParseMentions(object? value) { - if (value == null) - return null; - - if (value is JsonElement element && element.ValueKind == JsonValueKind.Array) + if (value is JsonElement { ValueKind: JsonValueKind.Array } element) { return element.EnumerateArray() .Where(e => e.GetProperty("type").GetString() == "Mention") @@ -554,27 +568,46 @@ public class ActivityPubActivityProcessor( }) .ToList(); } - + return null; } - private List? ParseTags(object? value) + private static Dictionary BuildMetadataFromActivity(Dictionary objectDict) { - if (value == null) - return null; - - if (value is JsonElement element && element.ValueKind == JsonValueKind.Array) + var metadata = new Dictionary(); + + var tagsValue = objectDict.GetValueOrDefault("tag"); + if (tagsValue is JsonElement { ValueKind: JsonValueKind.Array } tagsElement) { - return element.EnumerateArray() + var fediverseTags = tagsElement.EnumerateArray() .Where(e => e.GetProperty("type").GetString() == "Hashtag") - .Select(tag => new ContentTag + .Select(e => e.GetProperty("name").GetString()) + .ToList(); + + if (fediverseTags.Count > 0) + { + metadata["fediverseTags"] = fediverseTags; + } + } + + var emojiValue = objectDict.GetValueOrDefault("emoji"); + if (emojiValue is not JsonElement { ValueKind: JsonValueKind.Array } emojiElement) return metadata; + { + var emojis = emojiElement.EnumerateArray() + .Select(e => new { - Name = tag.GetProperty("name").GetString(), - Url = tag.GetProperty("href").GetString() + Shortcode = e.GetProperty("shortcode").GetString(), + StaticUrl = e.GetProperty("static_url").GetString(), + Url = e.GetProperty("url").GetString() }) .ToList(); + + if (emojis.Count > 0) + { + metadata["fediverseEmojis"] = emojis; + } } - - return null; + + return metadata; } } diff --git a/DysonNetwork.Sphere/AppDatabase.cs b/DysonNetwork.Sphere/AppDatabase.cs index a9d92be..2582b13 100644 --- a/DysonNetwork.Sphere/AppDatabase.cs +++ b/DysonNetwork.Sphere/AppDatabase.cs @@ -50,10 +50,7 @@ public class AppDatabase( public DbSet FediverseInstances { get; set; } = null!; public DbSet FediverseActors { get; set; } = null!; - public DbSet FediverseContents { get; set; } = null!; - public DbSet FediverseActivities { get; set; } = null!; public DbSet FediverseRelationships { get; set; } = null!; - public DbSet FediverseReactions { get; set; } = null!; public DbSet WebArticles { get; set; } = null!; public DbSet WebFeeds { get; set; } = null!; @@ -155,28 +152,6 @@ public class AppDatabase( .HasForeignKey(a => a.InstanceId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .HasOne(c => c.Actor) - .WithMany(a => a.Contents) - .HasForeignKey(c => c.ActorId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .HasOne(c => c.Instance) - .WithMany(i => i.Contents) - .HasForeignKey(c => c.InstanceId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasOne(a => a.Actor) - .WithMany(actor => actor.Activities) - .HasForeignKey(a => a.ActorId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .HasOne(a => a.Content) - .WithMany(c => c.Activities) - .HasForeignKey(a => a.ContentId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() .HasOne(r => r.Actor) .WithMany(a => a.FollowingRelationships) @@ -188,17 +163,6 @@ public class AppDatabase( .HasForeignKey(r => r.TargetActorId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .HasOne(r => r.Content) - .WithMany(c => c.Reactions) - .HasForeignKey(r => r.ContentId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .HasOne(r => r.Actor) - .WithMany() - .HasForeignKey(r => r.ActorId) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.ApplySoftDeleteFilters(); } diff --git a/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.Designer.cs b/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.Designer.cs index b6f4c59..c411a12 100644 --- a/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.Designer.cs @@ -543,9 +543,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(2048)") .HasColumnName("announced_content_uri"); - b.Property>("Attachments") - .HasColumnType("jsonb") - .HasColumnName("attachments"); + // b.Property>("Attachments") + // .HasColumnType("jsonb") + // .HasColumnName("attachments"); b.Property("BoostCount") .HasColumnType("integer") @@ -571,9 +571,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("edited_at"); - b.Property>("Emojis") - .HasColumnType("jsonb") - .HasColumnName("emojis"); + // b.Property>("Emojis") + // .HasColumnType("jsonb") + // .HasColumnName("emojis"); b.Property("InReplyTo") .HasMaxLength(2048) @@ -601,9 +601,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("local_post_id"); - b.Property>("Mentions") - .HasColumnType("jsonb") - .HasColumnName("mentions"); + // b.Property>("Mentions") + // .HasColumnType("jsonb") + // .HasColumnName("mentions"); b.Property>("Metadata") .HasColumnType("jsonb") @@ -622,9 +622,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(4096)") .HasColumnName("summary"); - b.Property>("Tags") - .HasColumnType("jsonb") - .HasColumnName("tags"); + // b.Property>("Tags") + // .HasColumnType("jsonb") + // .HasColumnName("tags"); b.Property("Title") .HasMaxLength(1024) diff --git a/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.cs b/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.cs index 49e2191..aa55412 100644 --- a/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.cs +++ b/DysonNetwork.Sphere/Migrations/20251228100758_AddActivityPub.cs @@ -102,10 +102,10 @@ namespace DysonNetwork.Sphere.Migrations published_at = table.Column(type: "timestamp with time zone", nullable: true), edited_at = table.Column(type: "timestamp with time zone", nullable: true), is_sensitive = table.Column(type: "boolean", nullable: false), - attachments = table.Column>(type: "jsonb", nullable: true), - mentions = table.Column>(type: "jsonb", nullable: true), - tags = table.Column>(type: "jsonb", nullable: true), - emojis = table.Column>(type: "jsonb", nullable: true), + // attachments = table.Column>(type: "jsonb", nullable: true), + // mentions = table.Column>(type: "jsonb", nullable: true), + // tags = table.Column>(type: "jsonb", nullable: true), + // emojis = table.Column>(type: "jsonb", nullable: true), metadata = table.Column>(type: "jsonb", nullable: true), actor_id = table.Column(type: "uuid", nullable: false), instance_id = table.Column(type: "uuid", nullable: false), diff --git a/DysonNetwork.Sphere/Migrations/20251228165042_AddSeprateActorType.Designer.cs b/DysonNetwork.Sphere/Migrations/20251228165042_AddSeprateActorType.Designer.cs index a5267f7..e73cb5c 100644 --- a/DysonNetwork.Sphere/Migrations/20251228165042_AddSeprateActorType.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20251228165042_AddSeprateActorType.Designer.cs @@ -549,9 +549,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(2048)") .HasColumnName("announced_content_uri"); - b.Property>("Attachments") - .HasColumnType("jsonb") - .HasColumnName("attachments"); + // b.Property>("Attachments") + // .HasColumnType("jsonb") + // .HasColumnName("attachments"); b.Property("BoostCount") .HasColumnType("integer") @@ -577,9 +577,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("edited_at"); - b.Property>("Emojis") - .HasColumnType("jsonb") - .HasColumnName("emojis"); + // b.Property>("Emojis") + // .HasColumnType("jsonb") + // .HasColumnName("emojis"); b.Property("InReplyTo") .HasMaxLength(2048) @@ -607,9 +607,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("local_post_id"); - b.Property>("Mentions") - .HasColumnType("jsonb") - .HasColumnName("mentions"); + // b.Property>("Mentions") + // .HasColumnType("jsonb") + // .HasColumnName("mentions"); b.Property>("Metadata") .HasColumnType("jsonb") @@ -628,9 +628,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(4096)") .HasColumnName("summary"); - b.Property>("Tags") - .HasColumnType("jsonb") - .HasColumnName("tags"); + // b.Property>("Tags") + // .HasColumnType("jsonb") + // .HasColumnName("tags"); b.Property("Title") .HasMaxLength(1024) diff --git a/DysonNetwork.Sphere/Migrations/20251228173217_EnrichFediverseInstance.Designer.cs b/DysonNetwork.Sphere/Migrations/20251228173217_EnrichFediverseInstance.Designer.cs index e5b92aa..42e28a5 100644 --- a/DysonNetwork.Sphere/Migrations/20251228173217_EnrichFediverseInstance.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20251228173217_EnrichFediverseInstance.Designer.cs @@ -549,9 +549,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(2048)") .HasColumnName("announced_content_uri"); - b.Property>("Attachments") - .HasColumnType("jsonb") - .HasColumnName("attachments"); + // b.Property>("Attachments") + // .HasColumnType("jsonb") + // .HasColumnName("attachments"); b.Property("BoostCount") .HasColumnType("integer") @@ -577,9 +577,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("edited_at"); - b.Property>("Emojis") - .HasColumnType("jsonb") - .HasColumnName("emojis"); + // b.Property>("Emojis") + // .HasColumnType("jsonb") + // .HasColumnName("emojis"); b.Property("InReplyTo") .HasMaxLength(2048) @@ -607,9 +607,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("local_post_id"); - b.Property>("Mentions") - .HasColumnType("jsonb") - .HasColumnName("mentions"); + // b.Property>("Mentions") + // .HasColumnType("jsonb") + // .HasColumnName("mentions"); b.Property>("Metadata") .HasColumnType("jsonb") @@ -628,9 +628,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(4096)") .HasColumnName("summary"); - b.Property>("Tags") - .HasColumnType("jsonb") - .HasColumnName("tags"); + // b.Property>("Tags") + // .HasColumnType("jsonb") + // .HasColumnName("tags"); b.Property("Title") .HasMaxLength(1024) diff --git a/DysonNetwork.Sphere/Migrations/20251229163103_BetterLocalActor.Designer.cs b/DysonNetwork.Sphere/Migrations/20251229163103_BetterLocalActor.Designer.cs index 060ce4e..5457962 100644 --- a/DysonNetwork.Sphere/Migrations/20251229163103_BetterLocalActor.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20251229163103_BetterLocalActor.Designer.cs @@ -553,9 +553,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(2048)") .HasColumnName("announced_content_uri"); - b.Property>("Attachments") - .HasColumnType("jsonb") - .HasColumnName("attachments"); + // b.Property>("Attachments") + // .HasColumnType("jsonb") + // .HasColumnName("attachments"); b.Property("BoostCount") .HasColumnType("integer") @@ -581,9 +581,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("edited_at"); - b.Property>("Emojis") - .HasColumnType("jsonb") - .HasColumnName("emojis"); + // b.Property>("Emojis") + // .HasColumnType("jsonb") + // .HasColumnName("emojis"); b.Property("InReplyTo") .HasMaxLength(2048) @@ -611,9 +611,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("local_post_id"); - b.Property>("Mentions") - .HasColumnType("jsonb") - .HasColumnName("mentions"); + // b.Property>("Mentions") + // .HasColumnType("jsonb") + // .HasColumnName("mentions"); b.Property>("Metadata") .HasColumnType("jsonb") @@ -632,9 +632,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(4096)") .HasColumnName("summary"); - b.Property>("Tags") - .HasColumnType("jsonb") - .HasColumnName("tags"); + // b.Property>("Tags") + // .HasColumnType("jsonb") + // .HasColumnName("tags"); b.Property("Title") .HasMaxLength(1024) diff --git a/DysonNetwork.Sphere/Migrations/20251229174336_AddPublisherKeys.Designer.cs b/DysonNetwork.Sphere/Migrations/20251229174336_AddPublisherKeys.Designer.cs index 0cb3ac4..2237ee8 100644 --- a/DysonNetwork.Sphere/Migrations/20251229174336_AddPublisherKeys.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20251229174336_AddPublisherKeys.Designer.cs @@ -553,9 +553,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(2048)") .HasColumnName("announced_content_uri"); - b.Property>("Attachments") - .HasColumnType("jsonb") - .HasColumnName("attachments"); + // b.Property>("Attachments") + // .HasColumnType("jsonb") + // .HasColumnName("attachments"); b.Property("BoostCount") .HasColumnType("integer") @@ -581,9 +581,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("edited_at"); - b.Property>("Emojis") - .HasColumnType("jsonb") - .HasColumnName("emojis"); + // b.Property>("Emojis") + // .HasColumnType("jsonb") + // .HasColumnName("emojis"); b.Property("InReplyTo") .HasMaxLength(2048) @@ -611,9 +611,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("local_post_id"); - b.Property>("Mentions") - .HasColumnType("jsonb") - .HasColumnName("mentions"); + // b.Property>("Mentions") + // .HasColumnType("jsonb") + // .HasColumnName("mentions"); b.Property>("Metadata") .HasColumnType("jsonb") @@ -632,9 +632,9 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(4096)") .HasColumnName("summary"); - b.Property>("Tags") - .HasColumnType("jsonb") - .HasColumnName("tags"); + // b.Property>("Tags") + // .HasColumnType("jsonb") + // .HasColumnName("tags"); b.Property("Title") .HasMaxLength(1024) diff --git a/DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.Designer.cs b/DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.Designer.cs new file mode 100644 index 0000000..60ce417 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.Designer.cs @@ -0,0 +1,2385 @@ +// +using System; +using System.Collections.Generic; +using System.Text.Json; +using DysonNetwork.Shared.Models; +using DysonNetwork.Sphere; +using DysonNetwork.Sphere.WebReader; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + [DbContext(typeof(AppDatabase))] + [Migration("20251230153545_MergeFediverseDataClass")] + partial class MergeFediverseDataClass + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("BreakUntil") + .HasColumnType("timestamp with time zone") + .HasColumnName("break_until"); + + b.Property("ChatRoomId") + .HasColumnType("uuid") + .HasColumnName("chat_room_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("InvitedById") + .HasColumnType("uuid") + .HasColumnName("invited_by_id"); + + b.Property("JoinedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("joined_at"); + + b.Property("LastReadAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_read_at"); + + b.Property("LeaveAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("leave_at"); + + b.Property("Nick") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("nick"); + + b.Property("Notify") + .HasColumnType("integer") + .HasColumnName("notify"); + + b.Property("TimeoutCause") + .HasColumnType("jsonb") + .HasColumnName("timeout_cause"); + + b.Property("TimeoutUntil") + .HasColumnType("timestamp with time zone") + .HasColumnName("timeout_until"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_chat_members"); + + b.HasAlternateKey("ChatRoomId", "AccountId") + .HasName("ak_chat_members_chat_room_id_account_id"); + + b.HasIndex("InvitedById") + .HasDatabaseName("ix_chat_members_invited_by_id"); + + b.ToTable("chat_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property>("Attachments") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("attachments"); + + b.Property("ChatRoomId") + .HasColumnType("uuid") + .HasColumnName("chat_room_id"); + + b.Property("Content") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("content"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("EditedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("edited_at"); + + b.Property("ForwardedMessageId") + .HasColumnType("uuid") + .HasColumnName("forwarded_message_id"); + + b.PrimitiveCollection("MembersMentioned") + .HasColumnType("jsonb") + .HasColumnName("members_mentioned"); + + b.Property>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Nonce") + .IsRequired() + .HasMaxLength(36) + .HasColumnType("character varying(36)") + .HasColumnName("nonce"); + + b.Property("RepliedMessageId") + .HasColumnType("uuid") + .HasColumnName("replied_message_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_id"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_chat_messages"); + + b.HasIndex("ChatRoomId") + .HasDatabaseName("ix_chat_messages_chat_room_id"); + + b.HasIndex("ForwardedMessageId") + .HasDatabaseName("ix_chat_messages_forwarded_message_id"); + + b.HasIndex("RepliedMessageId") + .HasDatabaseName("ix_chat_messages_replied_message_id"); + + b.HasIndex("SenderId") + .HasDatabaseName("ix_chat_messages_sender_id"); + + b.ToTable("chat_messages", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMessageReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Attitude") + .HasColumnType("integer") + .HasColumnName("attitude"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("MessageId") + .HasColumnType("uuid") + .HasColumnName("message_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_id"); + + b.Property("Symbol") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("symbol"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_chat_reactions"); + + b.HasIndex("MessageId") + .HasDatabaseName("ix_chat_reactions_message_id"); + + b.HasIndex("SenderId") + .HasDatabaseName("ix_chat_reactions_sender_id"); + + b.ToTable("chat_reactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatRoom", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Background") + .HasColumnType("jsonb") + .HasColumnName("background"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("IsCommunity") + .HasColumnType("boolean") + .HasColumnName("is_community"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("is_public"); + + b.Property("Name") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("Picture") + .HasColumnType("jsonb") + .HasColumnName("picture"); + + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_id"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_chat_rooms"); + + b.ToTable("chat_rooms", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActor", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AvatarUrl") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("avatar_url"); + + b.Property("Bio") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("bio"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("DisplayName") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("display_name"); + + b.Property("FeaturedUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("featured_uri"); + + b.Property("FollowersUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("followers_uri"); + + b.Property("FollowingUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("following_uri"); + + b.Property("HeaderUrl") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("header_url"); + + b.Property("InboxUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("inbox_uri"); + + b.Property("InstanceId") + .HasColumnType("uuid") + .HasColumnName("instance_id"); + + b.Property("IsBot") + .HasColumnType("boolean") + .HasColumnName("is_bot"); + + b.Property("IsDiscoverable") + .HasColumnType("boolean") + .HasColumnName("is_discoverable"); + + b.Property("IsLocked") + .HasColumnType("boolean") + .HasColumnName("is_locked"); + + b.Property("LastActivityAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_activity_at"); + + b.Property("LastFetchedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_fetched_at"); + + b.Property>("Metadata") + .HasColumnType("jsonb") + .HasColumnName("metadata"); + + b.Property("OutboxUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("outbox_uri"); + + b.Property("PublicKey") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("public_key"); + + b.Property("PublicKeyId") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("public_key_id"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Uri") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("uri"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_fediverse_actors"); + + b.HasIndex("InstanceId") + .HasDatabaseName("ix_fediverse_actors_instance_id"); + + b.HasIndex("Uri") + .IsUnique() + .HasDatabaseName("ix_fediverse_actors_uri"); + + b.ToTable("fediverse_actors", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ActiveUsers") + .HasColumnType("integer") + .HasColumnName("active_users"); + + b.Property("BlockReason") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("block_reason"); + + b.Property("ContactAccountUsername") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("contact_account_username"); + + b.Property("ContactEmail") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("contact_email"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("Domain") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("domain"); + + b.Property("IconUrl") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("icon_url"); + + b.Property("IsBlocked") + .HasColumnType("boolean") + .HasColumnName("is_blocked"); + + b.Property("IsSilenced") + .HasColumnType("boolean") + .HasColumnName("is_silenced"); + + b.Property("LastActivityAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_activity_at"); + + b.Property("LastFetchedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_fetched_at"); + + b.Property>("Metadata") + .HasColumnType("jsonb") + .HasColumnName("metadata"); + + b.Property("MetadataFetchedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("metadata_fetched_at"); + + b.Property("Name") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("name"); + + b.Property("Software") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("software"); + + b.Property("ThumbnailUrl") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("thumbnail_url"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Version") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_fediverse_instances"); + + b.HasIndex("Domain") + .IsUnique() + .HasDatabaseName("ix_fediverse_instances_domain"); + + b.ToTable("fediverse_instances", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ActorId") + .HasColumnType("uuid") + .HasColumnName("actor_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FollowedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("followed_at"); + + b.Property("FollowedBackAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("followed_back_at"); + + b.Property("IsBlocking") + .HasColumnType("boolean") + .HasColumnName("is_blocking"); + + b.Property("IsFollowedBy") + .HasColumnType("boolean") + .HasColumnName("is_followed_by"); + + b.Property("IsFollowing") + .HasColumnType("boolean") + .HasColumnName("is_following"); + + b.Property("IsMuting") + .HasColumnType("boolean") + .HasColumnName("is_muting"); + + b.Property("RejectReason") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("reject_reason"); + + b.Property("State") + .HasColumnType("integer") + .HasColumnName("state"); + + b.Property("TargetActorId") + .HasColumnType("uuid") + .HasColumnName("target_actor_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_fediverse_relationships"); + + b.HasIndex("ActorId") + .HasDatabaseName("ix_fediverse_relationships_actor_id"); + + b.HasIndex("TargetActorId") + .HasDatabaseName("ix_fediverse_relationships_target_actor_id"); + + b.ToTable("fediverse_relationships", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPoll", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("ended_at"); + + b.Property("IsAnonymous") + .HasColumnType("boolean") + .HasColumnName("is_anonymous"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Title") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("title"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_polls"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_polls_publisher_id"); + + b.ToTable("polls", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPollAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property>("Answer") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("answer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PollId") + .HasColumnType("uuid") + .HasColumnName("poll_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_poll_answers"); + + b.HasIndex("PollId") + .HasDatabaseName("ix_poll_answers_poll_id"); + + b.ToTable("poll_answers", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPollQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("IsRequired") + .HasColumnType("boolean") + .HasColumnName("is_required"); + + b.Property>("Options") + .HasColumnType("jsonb") + .HasColumnName("options"); + + b.Property("Order") + .HasColumnType("integer") + .HasColumnName("order"); + + b.Property("PollId") + .HasColumnType("uuid") + .HasColumnName("poll_id"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("title"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_poll_questions"); + + b.HasIndex("PollId") + .HasDatabaseName("ix_poll_questions_poll_id"); + + b.ToTable("poll_questions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ActorId") + .HasColumnType("uuid") + .HasColumnName("actor_id"); + + b.Property>("Attachments") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("attachments"); + + b.Property("AwardedScore") + .HasColumnType("numeric") + .HasColumnName("awarded_score"); + + b.Property("BoostCount") + .HasColumnType("integer") + .HasColumnName("boost_count"); + + b.Property("Content") + .HasColumnType("text") + .HasColumnName("content"); + + b.Property("ContentType") + .HasColumnType("integer") + .HasColumnName("content_type"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("Downvotes") + .HasColumnType("integer") + .HasColumnName("downvotes"); + + b.Property("EditedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("edited_at"); + + b.Property("EmbedView") + .HasColumnType("jsonb") + .HasColumnName("embed_view"); + + b.Property("FediverseType") + .HasColumnType("integer") + .HasColumnName("fediverse_type"); + + b.Property("FediverseUri") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("fediverse_uri"); + + b.Property("ForwardedGone") + .HasColumnType("boolean") + .HasColumnName("forwarded_gone"); + + b.Property("ForwardedPostId") + .HasColumnType("uuid") + .HasColumnName("forwarded_post_id"); + + b.Property("Language") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("language"); + + b.Property("LikeCount") + .HasColumnType("integer") + .HasColumnName("like_count"); + + b.Property>("Mentions") + .HasColumnType("jsonb") + .HasColumnName("mentions"); + + b.Property>("Metadata") + .HasColumnType("jsonb") + .HasColumnName("metadata"); + + b.Property("PinMode") + .HasColumnType("integer") + .HasColumnName("pin_mode"); + + b.Property("PublishedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("published_at"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_id"); + + b.Property("RepliedGone") + .HasColumnType("boolean") + .HasColumnName("replied_gone"); + + b.Property("RepliedPostId") + .HasColumnType("uuid") + .HasColumnName("replied_post_id"); + + b.Property("RepliesCount") + .HasColumnType("integer") + .HasColumnName("replies_count"); + + b.PrimitiveCollection("SensitiveMarks") + .HasColumnType("jsonb") + .HasColumnName("sensitive_marks"); + + b.Property("Slug") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("slug"); + + b.Property("Title") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("title"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Upvotes") + .HasColumnType("integer") + .HasColumnName("upvotes"); + + b.Property("ViewsTotal") + .HasColumnType("integer") + .HasColumnName("views_total"); + + b.Property("ViewsUnique") + .HasColumnType("integer") + .HasColumnName("views_unique"); + + b.Property("Visibility") + .HasColumnType("integer") + .HasColumnName("visibility"); + + b.HasKey("Id") + .HasName("pk_posts"); + + b.HasIndex("ActorId") + .HasDatabaseName("ix_posts_actor_id"); + + b.HasIndex("ForwardedPostId") + .HasDatabaseName("ix_posts_forwarded_post_id"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_posts_publisher_id"); + + b.HasIndex("RepliedPostId") + .HasDatabaseName("ix_posts_replied_post_id"); + + b.ToTable("posts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostAward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("Attitude") + .HasColumnType("integer") + .HasColumnName("attitude"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Message") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("message"); + + b.Property("PostId") + .HasColumnType("uuid") + .HasColumnName("post_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_awards"); + + b.HasIndex("PostId") + .HasDatabaseName("ix_post_awards_post_id"); + + b.ToTable("post_awards", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_categories"); + + b.ToTable("post_categories", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostCategorySubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CategoryId") + .HasColumnType("uuid") + .HasColumnName("category_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("TagId") + .HasColumnType("uuid") + .HasColumnName("tag_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_category_subscriptions"); + + b.HasIndex("CategoryId") + .HasDatabaseName("ix_post_category_subscriptions_category_id"); + + b.HasIndex("TagId") + .HasDatabaseName("ix_post_category_subscriptions_tag_id"); + + b.ToTable("post_category_subscriptions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_collections"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_post_collections_publisher_id"); + + b.ToTable("post_collections", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostFeaturedRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FeaturedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("featured_at"); + + b.Property("PostId") + .HasColumnType("uuid") + .HasColumnName("post_id"); + + b.Property("SocialCredits") + .HasColumnType("integer") + .HasColumnName("social_credits"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_featured_records"); + + b.HasIndex("PostId") + .HasDatabaseName("ix_post_featured_records_post_id"); + + b.ToTable("post_featured_records", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("ActorId") + .HasColumnType("uuid") + .HasColumnName("actor_id"); + + b.Property("Attitude") + .HasColumnType("integer") + .HasColumnName("attitude"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FediverseUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("fediverse_uri"); + + b.Property("IsLocal") + .HasColumnType("boolean") + .HasColumnName("is_local"); + + b.Property("PostId") + .HasColumnType("uuid") + .HasColumnName("post_id"); + + b.Property("Symbol") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("symbol"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_reactions"); + + b.HasIndex("ActorId") + .HasDatabaseName("ix_post_reactions_actor_id"); + + b.HasIndex("PostId") + .HasDatabaseName("ix_post_reactions_post_id"); + + b.ToTable("post_reactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_post_tags"); + + b.ToTable("post_tags", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisher", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Background") + .HasColumnType("jsonb") + .HasColumnName("background"); + + b.Property("Bio") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("bio"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("name"); + + b.Property("Nick") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("nick"); + + b.Property("Picture") + .HasColumnType("jsonb") + .HasColumnName("picture"); + + b.Property("PrivateKeyPem") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("private_key_pem"); + + b.Property("PublicKeyPem") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("public_key_pem"); + + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_id"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Verification") + .HasColumnType("jsonb") + .HasColumnName("verification"); + + b.HasKey("Id") + .HasName("pk_publishers"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_publishers_name"); + + b.ToTable("publishers", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisherFeature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("Flag") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("flag"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_publisher_features"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_publisher_features_publisher_id"); + + b.ToTable("publisher_features", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisherMember", b => + { + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("JoinedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("joined_at"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("PublisherId", "AccountId") + .HasName("pk_publisher_members"); + + b.ToTable("publisher_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisherSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("Tier") + .HasColumnType("integer") + .HasColumnName("tier"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_publisher_subscriptions"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_publisher_subscriptions_publisher_id"); + + b.ToTable("publisher_subscriptions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnRealtimeCall", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("EndedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("ended_at"); + + b.Property("ProviderName") + .HasColumnType("text") + .HasColumnName("provider_name"); + + b.Property("RoomId") + .HasColumnType("uuid") + .HasColumnName("room_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_id"); + + b.Property("SessionId") + .HasColumnType("text") + .HasColumnName("session_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UpstreamConfigJson") + .HasColumnType("jsonb") + .HasColumnName("upstream"); + + b.HasKey("Id") + .HasName("pk_chat_realtime_call"); + + b.HasIndex("RoomId") + .HasDatabaseName("ix_chat_realtime_call_room_id"); + + b.HasIndex("SenderId") + .HasDatabaseName("ix_chat_realtime_call_sender_id"); + + b.ToTable("chat_realtime_call", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnSticker", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Image") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("image"); + + b.Property("PackId") + .HasColumnType("uuid") + .HasColumnName("pack_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_stickers"); + + b.HasIndex("PackId") + .HasDatabaseName("ix_stickers_pack_id"); + + b.HasIndex("Slug") + .HasDatabaseName("ix_stickers_slug"); + + b.ToTable("stickers", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.StickerPack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("Icon") + .HasColumnType("jsonb") + .HasColumnName("icon"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("Prefix") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("prefix"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_sticker_packs"); + + b.HasIndex("Prefix") + .IsUnique() + .HasDatabaseName("ix_sticker_packs_prefix"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_sticker_packs_publisher_id"); + + b.ToTable("sticker_packs", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.StickerPackOwnership", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PackId") + .HasColumnType("uuid") + .HasColumnName("pack_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_sticker_pack_ownerships"); + + b.HasIndex("PackId") + .HasDatabaseName("ix_sticker_pack_ownerships_pack_id"); + + b.ToTable("sticker_pack_ownerships", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebArticle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Author") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("author"); + + b.Property("Content") + .HasColumnType("text") + .HasColumnName("content"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FeedId") + .HasColumnType("uuid") + .HasColumnName("feed_id"); + + b.Property>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Preview") + .HasColumnType("jsonb") + .HasColumnName("preview"); + + b.Property("PublishedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("published_at"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("title"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("url"); + + b.HasKey("Id") + .HasName("pk_web_articles"); + + b.HasIndex("FeedId") + .HasDatabaseName("ix_web_articles_feed_id"); + + b.HasIndex("Url") + .IsUnique() + .HasDatabaseName("ix_web_articles_url"); + + b.ToTable("web_articles", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeed", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Config") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("config"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("Description") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("description"); + + b.Property("Preview") + .HasColumnType("jsonb") + .HasColumnName("preview"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("title"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("url"); + + b.HasKey("Id") + .HasName("pk_web_feeds"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_web_feeds_publisher_id"); + + b.HasIndex("Url") + .IsUnique() + .HasDatabaseName("ix_web_feeds_url"); + + b.ToTable("web_feeds", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeedSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("FeedId") + .HasColumnType("uuid") + .HasColumnName("feed_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_web_feed_subscriptions"); + + b.HasIndex("FeedId") + .HasDatabaseName("ix_web_feed_subscriptions_feed_id"); + + b.ToTable("web_feed_subscriptions", (string)null); + }); + + modelBuilder.Entity("SnPostSnPostCategory", b => + { + b.Property("CategoriesId") + .HasColumnType("uuid") + .HasColumnName("categories_id"); + + b.Property("PostsId") + .HasColumnType("uuid") + .HasColumnName("posts_id"); + + b.HasKey("CategoriesId", "PostsId") + .HasName("pk_post_category_links"); + + b.HasIndex("PostsId") + .HasDatabaseName("ix_post_category_links_posts_id"); + + b.ToTable("post_category_links", (string)null); + }); + + modelBuilder.Entity("SnPostSnPostCollection", b => + { + b.Property("CollectionsId") + .HasColumnType("uuid") + .HasColumnName("collections_id"); + + b.Property("PostsId") + .HasColumnType("uuid") + .HasColumnName("posts_id"); + + b.HasKey("CollectionsId", "PostsId") + .HasName("pk_post_collection_links"); + + b.HasIndex("PostsId") + .HasDatabaseName("ix_post_collection_links_posts_id"); + + b.ToTable("post_collection_links", (string)null); + }); + + modelBuilder.Entity("SnPostSnPostTag", b => + { + b.Property("PostsId") + .HasColumnType("uuid") + .HasColumnName("posts_id"); + + b.Property("TagsId") + .HasColumnType("uuid") + .HasColumnName("tags_id"); + + b.HasKey("PostsId", "TagsId") + .HasName("pk_post_tag_links"); + + b.HasIndex("TagsId") + .HasDatabaseName("ix_post_tag_links_tags_id"); + + b.ToTable("post_tag_links", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMember", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnChatRoom", "ChatRoom") + .WithMany("Members") + .HasForeignKey("ChatRoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_members_chat_rooms_chat_room_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnChatMember", "InvitedBy") + .WithMany() + .HasForeignKey("InvitedById") + .HasConstraintName("fk_chat_members_chat_members_invited_by_id"); + + b.Navigation("ChatRoom"); + + b.Navigation("InvitedBy"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMessage", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnChatRoom", "ChatRoom") + .WithMany() + .HasForeignKey("ChatRoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_messages_chat_rooms_chat_room_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnChatMessage", "ForwardedMessage") + .WithMany() + .HasForeignKey("ForwardedMessageId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_chat_messages_chat_messages_forwarded_message_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnChatMessage", "RepliedMessage") + .WithMany() + .HasForeignKey("RepliedMessageId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_chat_messages_chat_messages_replied_message_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnChatMember", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_messages_chat_members_sender_id"); + + b.Navigation("ChatRoom"); + + b.Navigation("ForwardedMessage"); + + b.Navigation("RepliedMessage"); + + b.Navigation("Sender"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMessageReaction", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnChatMessage", "Message") + .WithMany("Reactions") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_reactions_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnChatMember", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_reactions_chat_members_sender_id"); + + b.Navigation("Message"); + + b.Navigation("Sender"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActor", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnFediverseInstance", "Instance") + .WithMany("Actors") + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_fediverse_actors_fediverse_instances_instance_id"); + + b.Navigation("Instance"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseRelationship", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") + .WithMany("FollowingRelationships") + .HasForeignKey("ActorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_fediverse_relationships_fediverse_actors_actor_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "TargetActor") + .WithMany("FollowerRelationships") + .HasForeignKey("TargetActorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_fediverse_relationships_fediverse_actors_target_actor_id"); + + b.Navigation("Actor"); + + b.Navigation("TargetActor"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPoll", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany("Polls") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_polls_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPollAnswer", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPoll", "Poll") + .WithMany() + .HasForeignKey("PollId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_poll_answers_polls_poll_id"); + + b.Navigation("Poll"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPollQuestion", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPoll", "Poll") + .WithMany("Questions") + .HasForeignKey("PollId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_poll_questions_polls_poll_id"); + + b.Navigation("Poll"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPost", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .HasConstraintName("fk_posts_fediverse_actors_actor_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPost", "ForwardedPost") + .WithMany() + .HasForeignKey("ForwardedPostId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_posts_posts_forwarded_post_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany("Posts") + .HasForeignKey("PublisherId") + .HasConstraintName("fk_posts_publishers_publisher_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPost", "RepliedPost") + .WithMany() + .HasForeignKey("RepliedPostId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_posts_posts_replied_post_id"); + + b.Navigation("Actor"); + + b.Navigation("ForwardedPost"); + + b.Navigation("Publisher"); + + b.Navigation("RepliedPost"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostAward", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPost", "Post") + .WithMany("Awards") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_awards_posts_post_id"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostCategorySubscription", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPostCategory", "Category") + .WithMany() + .HasForeignKey("CategoryId") + .HasConstraintName("fk_post_category_subscriptions_post_categories_category_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPostTag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .HasConstraintName("fk_post_category_subscriptions_post_tags_tag_id"); + + b.Navigation("Category"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostCollection", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany("Collections") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collections_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostFeaturedRecord", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPost", "Post") + .WithMany("FeaturedRecords") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_featured_records_posts_post_id"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostReaction", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .HasConstraintName("fk_post_reactions_fediverse_actors_actor_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPost", "Post") + .WithMany("Reactions") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_posts_post_id"); + + b.Navigation("Actor"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisherFeature", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany("Features") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_features_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisherMember", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany("Members") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisherSubscription", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany("Subscriptions") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnRealtimeCall", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnChatRoom", "Room") + .WithMany() + .HasForeignKey("RoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_realtime_call_chat_rooms_room_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnChatMember", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_realtime_call_chat_members_sender_id"); + + b.Navigation("Room"); + + b.Navigation("Sender"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnSticker", b => + { + b.HasOne("DysonNetwork.Shared.Models.StickerPack", "Pack") + .WithMany("Stickers") + .HasForeignKey("PackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_sticker_packs_pack_id"); + + b.Navigation("Pack"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.StickerPack", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_sticker_packs_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.StickerPackOwnership", b => + { + b.HasOne("DysonNetwork.Shared.Models.StickerPack", "Pack") + .WithMany("Ownerships") + .HasForeignKey("PackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_sticker_pack_ownerships_sticker_packs_pack_id"); + + b.Navigation("Pack"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebArticle", b => + { + b.HasOne("DysonNetwork.Sphere.WebReader.WebFeed", "Feed") + .WithMany("Articles") + .HasForeignKey("FeedId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_web_articles_web_feeds_feed_id"); + + b.Navigation("Feed"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeed", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_web_feeds_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeedSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.WebReader.WebFeed", "Feed") + .WithMany() + .HasForeignKey("FeedId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_web_feed_subscriptions_web_feeds_feed_id"); + + b.Navigation("Feed"); + }); + + modelBuilder.Entity("SnPostSnPostCategory", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPostCategory", null) + .WithMany() + .HasForeignKey("CategoriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_category_links_post_categories_categories_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPost", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_category_links_posts_posts_id"); + }); + + modelBuilder.Entity("SnPostSnPostCollection", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPostCollection", null) + .WithMany() + .HasForeignKey("CollectionsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collection_links_post_collections_collections_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPost", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collection_links_posts_posts_id"); + }); + + modelBuilder.Entity("SnPostSnPostTag", b => + { + b.HasOne("DysonNetwork.Shared.Models.SnPost", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_tag_links_posts_posts_id"); + + b.HasOne("DysonNetwork.Shared.Models.SnPostTag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_tag_links_post_tags_tags_id"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatMessage", b => + { + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnChatRoom", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActor", b => + { + b.Navigation("FollowerRelationships"); + + b.Navigation("FollowingRelationships"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseInstance", b => + { + b.Navigation("Actors"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPoll", b => + { + b.Navigation("Questions"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPost", b => + { + b.Navigation("Awards"); + + b.Navigation("FeaturedRecords"); + + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.SnPublisher", b => + { + b.Navigation("Collections"); + + b.Navigation("Features"); + + b.Navigation("Members"); + + b.Navigation("Polls"); + + b.Navigation("Posts"); + + b.Navigation("Subscriptions"); + }); + + modelBuilder.Entity("DysonNetwork.Shared.Models.StickerPack", b => + { + b.Navigation("Ownerships"); + + b.Navigation("Stickers"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeed", b => + { + b.Navigation("Articles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.cs b/DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.cs new file mode 100644 index 0000000..44f81b8 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20251230153545_MergeFediverseDataClass.cs @@ -0,0 +1,433 @@ +using System; +using System.Collections.Generic; +using DysonNetwork.Shared.Models; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + /// + public partial class MergeFediverseDataClass : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_posts_publishers_publisher_id", + table: "posts"); + + migrationBuilder.DropTable( + name: "fediverse_activities"); + + migrationBuilder.DropTable( + name: "fediverse_reactions"); + + migrationBuilder.DropTable( + name: "fediverse_contents"); + + migrationBuilder.RenameColumn( + name: "meta", + table: "posts", + newName: "metadata"); + + migrationBuilder.AlterColumn( + name: "publisher_id", + table: "posts", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AddColumn( + name: "actor_id", + table: "posts", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "boost_count", + table: "posts", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "content_type", + table: "posts", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "fediverse_type", + table: "posts", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "fediverse_uri", + table: "posts", + type: "character varying(8192)", + maxLength: 8192, + nullable: true); + + migrationBuilder.AddColumn( + name: "language", + table: "posts", + type: "character varying(2048)", + maxLength: 2048, + nullable: true); + + migrationBuilder.AddColumn( + name: "like_count", + table: "posts", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn>( + name: "mentions", + table: "posts", + type: "jsonb", + nullable: true); + + migrationBuilder.AddColumn( + name: "replies_count", + table: "posts", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AlterColumn( + name: "account_id", + table: "post_reactions", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AddColumn( + name: "actor_id", + table: "post_reactions", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "fediverse_uri", + table: "post_reactions", + type: "character varying(2048)", + maxLength: 2048, + nullable: true); + + migrationBuilder.AddColumn( + name: "is_local", + table: "post_reactions", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.CreateIndex( + name: "ix_posts_actor_id", + table: "posts", + column: "actor_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_reactions_actor_id", + table: "post_reactions", + column: "actor_id"); + + migrationBuilder.AddForeignKey( + name: "fk_post_reactions_fediverse_actors_actor_id", + table: "post_reactions", + column: "actor_id", + principalTable: "fediverse_actors", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "fk_posts_fediverse_actors_actor_id", + table: "posts", + column: "actor_id", + principalTable: "fediverse_actors", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "fk_posts_publishers_publisher_id", + table: "posts", + column: "publisher_id", + principalTable: "publishers", + principalColumn: "id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_post_reactions_fediverse_actors_actor_id", + table: "post_reactions"); + + migrationBuilder.DropForeignKey( + name: "fk_posts_fediverse_actors_actor_id", + table: "posts"); + + migrationBuilder.DropForeignKey( + name: "fk_posts_publishers_publisher_id", + table: "posts"); + + migrationBuilder.DropIndex( + name: "ix_posts_actor_id", + table: "posts"); + + migrationBuilder.DropIndex( + name: "ix_post_reactions_actor_id", + table: "post_reactions"); + + migrationBuilder.DropColumn( + name: "actor_id", + table: "posts"); + + migrationBuilder.DropColumn( + name: "boost_count", + table: "posts"); + + migrationBuilder.DropColumn( + name: "content_type", + table: "posts"); + + migrationBuilder.DropColumn( + name: "fediverse_type", + table: "posts"); + + migrationBuilder.DropColumn( + name: "fediverse_uri", + table: "posts"); + + migrationBuilder.DropColumn( + name: "language", + table: "posts"); + + migrationBuilder.DropColumn( + name: "like_count", + table: "posts"); + + migrationBuilder.DropColumn( + name: "mentions", + table: "posts"); + + migrationBuilder.DropColumn( + name: "replies_count", + table: "posts"); + + migrationBuilder.DropColumn( + name: "actor_id", + table: "post_reactions"); + + migrationBuilder.DropColumn( + name: "fediverse_uri", + table: "post_reactions"); + + migrationBuilder.DropColumn( + name: "is_local", + table: "post_reactions"); + + migrationBuilder.RenameColumn( + name: "metadata", + table: "posts", + newName: "meta"); + + migrationBuilder.AlterColumn( + name: "publisher_id", + table: "posts", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "account_id", + table: "post_reactions", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.CreateTable( + name: "fediverse_contents", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + actor_id = table.Column(type: "uuid", nullable: false), + instance_id = table.Column(type: "uuid", nullable: false), + announced_content_uri = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), + boost_count = table.Column(type: "integer", nullable: false), + content = table.Column(type: "text", nullable: true), + content_html = table.Column(type: "text", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true), + edited_at = table.Column(type: "timestamp with time zone", nullable: true), + in_reply_to = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), + is_sensitive = table.Column(type: "boolean", nullable: false), + language = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), + like_count = table.Column(type: "integer", nullable: false), + local_post_id = table.Column(type: "uuid", nullable: true), + metadata = table.Column>(type: "jsonb", nullable: true), + published_at = table.Column(type: "timestamp with time zone", nullable: true), + reply_count = table.Column(type: "integer", nullable: false), + summary = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + title = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + type = table.Column(type: "integer", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + uri = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_fediverse_contents", x => x.id); + table.ForeignKey( + name: "fk_fediverse_contents_fediverse_actors_actor_id", + column: x => x.actor_id, + principalTable: "fediverse_actors", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_fediverse_contents_fediverse_instances_instance_id", + column: x => x.instance_id, + principalTable: "fediverse_instances", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "fediverse_activities", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + actor_id = table.Column(type: "uuid", nullable: false), + content_id = table.Column(type: "uuid", nullable: true), + target_actor_id = table.Column(type: "uuid", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true), + error_message = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + is_local = table.Column(type: "boolean", nullable: false), + local_account_id = table.Column(type: "uuid", nullable: true), + local_post_id = table.Column(type: "uuid", nullable: true), + object_uri = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), + published_at = table.Column(type: "timestamp with time zone", nullable: true), + raw_data = table.Column>(type: "jsonb", nullable: true), + status = table.Column(type: "integer", nullable: false), + target_uri = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true), + type = table.Column(type: "integer", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + uri = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_fediverse_activities", x => x.id); + table.ForeignKey( + name: "fk_fediverse_activities_fediverse_actors_actor_id", + column: x => x.actor_id, + principalTable: "fediverse_actors", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_fediverse_activities_fediverse_actors_target_actor_id", + column: x => x.target_actor_id, + principalTable: "fediverse_actors", + principalColumn: "id"); + table.ForeignKey( + name: "fk_fediverse_activities_fediverse_contents_content_id", + column: x => x.content_id, + principalTable: "fediverse_contents", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "fediverse_reactions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + actor_id = table.Column(type: "uuid", nullable: false), + content_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true), + emoji = table.Column(type: "character varying(64)", maxLength: 64, nullable: true), + is_local = table.Column(type: "boolean", nullable: false), + local_account_id = table.Column(type: "uuid", nullable: true), + local_reaction_id = table.Column(type: "uuid", nullable: true), + type = table.Column(type: "integer", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + uri = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_fediverse_reactions", x => x.id); + table.ForeignKey( + name: "fk_fediverse_reactions_fediverse_actors_actor_id", + column: x => x.actor_id, + principalTable: "fediverse_actors", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_fediverse_reactions_fediverse_contents_content_id", + column: x => x.content_id, + principalTable: "fediverse_contents", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_activities_actor_id", + table: "fediverse_activities", + column: "actor_id"); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_activities_content_id", + table: "fediverse_activities", + column: "content_id"); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_activities_target_actor_id", + table: "fediverse_activities", + column: "target_actor_id"); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_contents_actor_id", + table: "fediverse_contents", + column: "actor_id"); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_contents_instance_id", + table: "fediverse_contents", + column: "instance_id"); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_contents_uri", + table: "fediverse_contents", + column: "uri", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_reactions_actor_id", + table: "fediverse_reactions", + column: "actor_id"); + + migrationBuilder.CreateIndex( + name: "ix_fediverse_reactions_content_id", + table: "fediverse_reactions", + column: "content_id"); + + migrationBuilder.AddForeignKey( + name: "fk_posts_publishers_publisher_id", + table: "posts", + column: "publisher_id", + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs index ede9963..4086c13 100644 --- a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs @@ -302,101 +302,6 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("chat_rooms", (string)null); }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActivity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("ActorId") - .HasColumnType("uuid") - .HasColumnName("actor_id"); - - b.Property("ContentId") - .HasColumnType("uuid") - .HasColumnName("content_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ErrorMessage") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("error_message"); - - b.Property("IsLocal") - .HasColumnType("boolean") - .HasColumnName("is_local"); - - b.Property("LocalAccountId") - .HasColumnType("uuid") - .HasColumnName("local_account_id"); - - b.Property("LocalPostId") - .HasColumnType("uuid") - .HasColumnName("local_post_id"); - - b.Property("ObjectUri") - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("object_uri"); - - b.Property("PublishedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("published_at"); - - b.Property>("RawData") - .HasColumnType("jsonb") - .HasColumnName("raw_data"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("TargetActorId") - .HasColumnType("uuid") - .HasColumnName("target_actor_id"); - - b.Property("TargetUri") - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("target_uri"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Uri") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("uri"); - - b.HasKey("Id") - .HasName("pk_fediverse_activities"); - - b.HasIndex("ActorId") - .HasDatabaseName("ix_fediverse_activities_actor_id"); - - b.HasIndex("ContentId") - .HasDatabaseName("ix_fediverse_activities_content_id"); - - b.HasIndex("TargetActorId") - .HasDatabaseName("ix_fediverse_activities_target_actor_id"); - - b.ToTable("fediverse_activities", (string)null); - }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActor", b => { b.Property("Id") @@ -534,140 +439,6 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("fediverse_actors", (string)null); }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseContent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("ActorId") - .HasColumnType("uuid") - .HasColumnName("actor_id"); - - b.Property("AnnouncedContentUri") - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("announced_content_uri"); - - b.Property>("Attachments") - .HasColumnType("jsonb") - .HasColumnName("attachments"); - - b.Property("BoostCount") - .HasColumnType("integer") - .HasColumnName("boost_count"); - - b.Property("Content") - .HasColumnType("text") - .HasColumnName("content"); - - b.Property("ContentHtml") - .HasColumnType("text") - .HasColumnName("content_html"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("EditedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("edited_at"); - - b.Property>("Emojis") - .HasColumnType("jsonb") - .HasColumnName("emojis"); - - b.Property("InReplyTo") - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("in_reply_to"); - - b.Property("InstanceId") - .HasColumnType("uuid") - .HasColumnName("instance_id"); - - b.Property("IsSensitive") - .HasColumnType("boolean") - .HasColumnName("is_sensitive"); - - b.Property("Language") - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("language"); - - b.Property("LikeCount") - .HasColumnType("integer") - .HasColumnName("like_count"); - - b.Property("LocalPostId") - .HasColumnType("uuid") - .HasColumnName("local_post_id"); - - b.Property>("Mentions") - .HasColumnType("jsonb") - .HasColumnName("mentions"); - - b.Property>("Metadata") - .HasColumnType("jsonb") - .HasColumnName("metadata"); - - b.Property("PublishedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("published_at"); - - b.Property("ReplyCount") - .HasColumnType("integer") - .HasColumnName("reply_count"); - - b.Property("Summary") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("summary"); - - b.Property>("Tags") - .HasColumnType("jsonb") - .HasColumnName("tags"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Uri") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("uri"); - - b.HasKey("Id") - .HasName("pk_fediverse_contents"); - - b.HasIndex("ActorId") - .HasDatabaseName("ix_fediverse_contents_actor_id"); - - b.HasIndex("InstanceId") - .HasDatabaseName("ix_fediverse_contents_instance_id"); - - b.HasIndex("Uri") - .IsUnique() - .HasDatabaseName("ix_fediverse_contents_uri"); - - b.ToTable("fediverse_contents", (string)null); - }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseInstance", b => { b.Property("Id") @@ -776,72 +547,6 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("fediverse_instances", (string)null); }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseReaction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("ActorId") - .HasColumnType("uuid") - .HasColumnName("actor_id"); - - b.Property("ContentId") - .HasColumnType("uuid") - .HasColumnName("content_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Emoji") - .HasMaxLength(64) - .HasColumnType("character varying(64)") - .HasColumnName("emoji"); - - b.Property("IsLocal") - .HasColumnType("boolean") - .HasColumnName("is_local"); - - b.Property("LocalAccountId") - .HasColumnType("uuid") - .HasColumnName("local_account_id"); - - b.Property("LocalReactionId") - .HasColumnType("uuid") - .HasColumnName("local_reaction_id"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Uri") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)") - .HasColumnName("uri"); - - b.HasKey("Id") - .HasName("pk_fediverse_reactions"); - - b.HasIndex("ActorId") - .HasDatabaseName("ix_fediverse_reactions_actor_id"); - - b.HasIndex("ContentId") - .HasDatabaseName("ix_fediverse_reactions_content_id"); - - b.ToTable("fediverse_reactions", (string)null); - }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseRelationship", b => { b.Property("Id") @@ -1071,6 +776,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("id"); + b.Property("ActorId") + .HasColumnType("uuid") + .HasColumnName("actor_id"); + b.Property>("Attachments") .IsRequired() .HasColumnType("jsonb") @@ -1080,10 +789,18 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("numeric") .HasColumnName("awarded_score"); + b.Property("BoostCount") + .HasColumnType("integer") + .HasColumnName("boost_count"); + b.Property("Content") .HasColumnType("text") .HasColumnName("content"); + b.Property("ContentType") + .HasColumnType("integer") + .HasColumnName("content_type"); + b.Property("CreatedAt") .HasColumnType("timestamp with time zone") .HasColumnName("created_at"); @@ -1109,6 +826,15 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("jsonb") .HasColumnName("embed_view"); + b.Property("FediverseType") + .HasColumnType("integer") + .HasColumnName("fediverse_type"); + + b.Property("FediverseUri") + .HasMaxLength(8192) + .HasColumnType("character varying(8192)") + .HasColumnName("fediverse_uri"); + b.Property("ForwardedGone") .HasColumnType("boolean") .HasColumnName("forwarded_gone"); @@ -1117,9 +843,22 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("forwarded_post_id"); - b.Property>("Meta") + b.Property("Language") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("language"); + + b.Property("LikeCount") + .HasColumnType("integer") + .HasColumnName("like_count"); + + b.Property>("Mentions") .HasColumnType("jsonb") - .HasColumnName("meta"); + .HasColumnName("mentions"); + + b.Property>("Metadata") + .HasColumnType("jsonb") + .HasColumnName("metadata"); b.Property("PinMode") .HasColumnType("integer") @@ -1129,7 +868,7 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("published_at"); - b.Property("PublisherId") + b.Property("PublisherId") .HasColumnType("uuid") .HasColumnName("publisher_id"); @@ -1145,6 +884,10 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("replied_post_id"); + b.Property("RepliesCount") + .HasColumnType("integer") + .HasColumnName("replies_count"); + b.PrimitiveCollection("SensitiveMarks") .HasColumnType("jsonb") .HasColumnName("sensitive_marks"); @@ -1186,6 +929,9 @@ namespace DysonNetwork.Sphere.Migrations b.HasKey("Id") .HasName("pk_posts"); + b.HasIndex("ActorId") + .HasDatabaseName("ix_posts_actor_id"); + b.HasIndex("ForwardedPostId") .HasDatabaseName("ix_posts_forwarded_post_id"); @@ -1421,10 +1167,14 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("uuid") .HasColumnName("id"); - b.Property("AccountId") + b.Property("AccountId") .HasColumnType("uuid") .HasColumnName("account_id"); + b.Property("ActorId") + .HasColumnType("uuid") + .HasColumnName("actor_id"); + b.Property("Attitude") .HasColumnType("integer") .HasColumnName("attitude"); @@ -1437,6 +1187,15 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("deleted_at"); + b.Property("FediverseUri") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("fediverse_uri"); + + b.Property("IsLocal") + .HasColumnType("boolean") + .HasColumnName("is_local"); + b.Property("PostId") .HasColumnType("uuid") .HasColumnName("post_id"); @@ -1454,6 +1213,9 @@ namespace DysonNetwork.Sphere.Migrations b.HasKey("Id") .HasName("pk_post_reactions"); + b.HasIndex("ActorId") + .HasDatabaseName("ix_post_reactions_actor_id"); + b.HasIndex("PostId") .HasDatabaseName("ix_post_reactions_post_id"); @@ -2198,33 +1960,6 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Sender"); }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActivity", b => - { - b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") - .WithMany("Activities") - .HasForeignKey("ActorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_fediverse_activities_fediverse_actors_actor_id"); - - b.HasOne("DysonNetwork.Shared.Models.SnFediverseContent", "Content") - .WithMany("Activities") - .HasForeignKey("ContentId") - .OnDelete(DeleteBehavior.Cascade) - .HasConstraintName("fk_fediverse_activities_fediverse_contents_content_id"); - - b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "TargetActor") - .WithMany() - .HasForeignKey("TargetActorId") - .HasConstraintName("fk_fediverse_activities_fediverse_actors_target_actor_id"); - - b.Navigation("Actor"); - - b.Navigation("Content"); - - b.Navigation("TargetActor"); - }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActor", b => { b.HasOne("DysonNetwork.Shared.Models.SnFediverseInstance", "Instance") @@ -2237,48 +1972,6 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Instance"); }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseContent", b => - { - b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") - .WithMany("Contents") - .HasForeignKey("ActorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_fediverse_contents_fediverse_actors_actor_id"); - - b.HasOne("DysonNetwork.Shared.Models.SnFediverseInstance", "Instance") - .WithMany("Contents") - .HasForeignKey("InstanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_fediverse_contents_fediverse_instances_instance_id"); - - b.Navigation("Actor"); - - b.Navigation("Instance"); - }); - - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseReaction", b => - { - b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") - .WithMany() - .HasForeignKey("ActorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_fediverse_reactions_fediverse_actors_actor_id"); - - b.HasOne("DysonNetwork.Shared.Models.SnFediverseContent", "Content") - .WithMany("Reactions") - .HasForeignKey("ContentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_fediverse_reactions_fediverse_contents_content_id"); - - b.Navigation("Actor"); - - b.Navigation("Content"); - }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseRelationship", b => { b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") @@ -2338,6 +2031,11 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Shared.Models.SnPost", b => { + b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .HasConstraintName("fk_posts_fediverse_actors_actor_id"); + b.HasOne("DysonNetwork.Shared.Models.SnPost", "ForwardedPost") .WithMany() .HasForeignKey("ForwardedPostId") @@ -2347,8 +2045,6 @@ namespace DysonNetwork.Sphere.Migrations b.HasOne("DysonNetwork.Shared.Models.SnPublisher", "Publisher") .WithMany("Posts") .HasForeignKey("PublisherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() .HasConstraintName("fk_posts_publishers_publisher_id"); b.HasOne("DysonNetwork.Shared.Models.SnPost", "RepliedPost") @@ -2357,6 +2053,8 @@ namespace DysonNetwork.Sphere.Migrations .OnDelete(DeleteBehavior.Restrict) .HasConstraintName("fk_posts_posts_replied_post_id"); + b.Navigation("Actor"); + b.Navigation("ForwardedPost"); b.Navigation("Publisher"); @@ -2419,6 +2117,11 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Shared.Models.SnPostReaction", b => { + b.HasOne("DysonNetwork.Shared.Models.SnFediverseActor", "Actor") + .WithMany() + .HasForeignKey("ActorId") + .HasConstraintName("fk_post_reactions_fediverse_actors_actor_id"); + b.HasOne("DysonNetwork.Shared.Models.SnPost", "Post") .WithMany("Reactions") .HasForeignKey("PostId") @@ -2426,6 +2129,8 @@ namespace DysonNetwork.Sphere.Migrations .IsRequired() .HasConstraintName("fk_post_reactions_posts_post_id"); + b.Navigation("Actor"); + b.Navigation("Post"); }); @@ -2621,27 +2326,14 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseActor", b => { - b.Navigation("Activities"); - - b.Navigation("Contents"); - b.Navigation("FollowerRelationships"); b.Navigation("FollowingRelationships"); }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseContent", b => - { - b.Navigation("Activities"); - - b.Navigation("Reactions"); - }); - modelBuilder.Entity("DysonNetwork.Shared.Models.SnFediverseInstance", b => { b.Navigation("Actors"); - - b.Navigation("Contents"); }); modelBuilder.Entity("DysonNetwork.Shared.Models.SnPoll", b => diff --git a/DysonNetwork.Sphere/Post/PostActionController.cs b/DysonNetwork.Sphere/Post/PostActionController.cs index 82a6bc1..f7c1ffa 100644 --- a/DysonNetwork.Sphere/Post/PostActionController.cs +++ b/DysonNetwork.Sphere/Post/PostActionController.cs @@ -113,7 +113,7 @@ public class PostActionController( Visibility = request.Visibility ?? Shared.Models.PostVisibility.Public, PublishedAt = request.PublishedAt, Type = request.Type ?? Shared.Models.PostType.Moment, - Meta = request.Meta, + Metadata = request.Meta, EmbedView = request.EmbedView, Publisher = publisher, }; @@ -161,15 +161,15 @@ public class PostActionController( try { var pollEmbed = await polls.MakePollEmbed(request.PollId.Value); - post.Meta ??= new Dictionary(); + post.Metadata ??= new Dictionary(); if ( - !post.Meta.TryGetValue("embeds", out var existingEmbeds) + !post.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List ) - post.Meta["embeds"] = new List>(); - var embeds = (List>)post.Meta["embeds"]; + post.Metadata["embeds"] = new List>(); + var embeds = (List>)post.Metadata["embeds"]; embeds.Add(EmbeddableBase.ToDictionary(pollEmbed)); - post.Meta["embeds"] = embeds; + post.Metadata["embeds"] = embeds; } catch (Exception ex) { @@ -191,15 +191,15 @@ public class PostActionController( return BadRequest("You can only share funds that you created."); var fundEmbed = new FundEmbed { Id = request.FundId.Value }; - post.Meta ??= new Dictionary(); + post.Metadata ??= new Dictionary(); if ( - !post.Meta.TryGetValue("embeds", out var existingEmbeds) + !post.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List ) - post.Meta["embeds"] = new List>(); - var embeds = (List>)post.Meta["embeds"]; + post.Metadata["embeds"] = new List>(); + var embeds = (List>)post.Metadata["embeds"]; embeds.Add(EmbeddableBase.ToDictionary(fundEmbed)); - post.Meta["embeds"] = embeds; + post.Metadata["embeds"] = embeds; } catch (RpcException ex) when (ex.StatusCode == Grpc.Core.StatusCode.NotFound) { @@ -213,8 +213,8 @@ public class PostActionController( if (request.ThumbnailId is not null) { - post.Meta ??= new Dictionary(); - post.Meta["thumbnail"] = request.ThumbnailId; + post.Metadata ??= new Dictionary(); + post.Metadata["thumbnail"] = request.ThumbnailId; } try @@ -454,7 +454,7 @@ public class PostActionController( return NotFound(); var accountId = Guid.Parse(currentUser.Id); - if (!await pub.IsMemberWithRole(post.PublisherId, accountId, PublisherMemberRole.Editor)) + if (post.PublisherId == null || !await pub.IsMemberWithRole(post.PublisherId.Value, accountId, PublisherMemberRole.Editor)) return StatusCode(403, "You are not an editor of this publisher"); if (request.Mode == Shared.Models.PostPinMode.RealmPage && post.RealmId != null) @@ -518,7 +518,7 @@ public class PostActionController( return NotFound(); var accountId = Guid.Parse(currentUser.Id); - if (!await pub.IsMemberWithRole(post.PublisherId, accountId, PublisherMemberRole.Editor)) + if (post.PublisherId == null || !await pub.IsMemberWithRole(post.PublisherId.Value, accountId, PublisherMemberRole.Editor)) return StatusCode(403, "You are not an editor of this publisher"); if (post is { PinMode: Shared.Models.PostPinMode.RealmPage, RealmId: not null }) @@ -622,7 +622,7 @@ public class PostActionController( if (request.Type is not null) post.Type = request.Type.Value; if (request.Meta is not null) - post.Meta = request.Meta; + post.Metadata = request.Meta; // The same, this field can be null, so update it anyway. post.EmbedView = request.EmbedView; @@ -634,19 +634,19 @@ public class PostActionController( try { var pollEmbed = await polls.MakePollEmbed(request.PollId.Value); - post.Meta ??= new Dictionary(); + post.Metadata ??= new Dictionary(); if ( - !post.Meta.TryGetValue("embeds", out var existingEmbeds) + !post.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List ) - post.Meta["embeds"] = new List>(); - var embeds = (List>)post.Meta["embeds"]; + post.Metadata["embeds"] = new List>(); + var embeds = (List>)post.Metadata["embeds"]; // Remove all old poll embeds embeds.RemoveAll(e => e.TryGetValue("type", out var type) && type.ToString() == "poll" ); embeds.Add(EmbeddableBase.ToDictionary(pollEmbed)); - post.Meta["embeds"] = embeds; + post.Metadata["embeds"] = embeds; } catch (Exception ex) { @@ -655,13 +655,13 @@ public class PostActionController( } else { - post.Meta ??= new Dictionary(); + post.Metadata ??= new Dictionary(); if ( - !post.Meta.TryGetValue("embeds", out var existingEmbeds) + !post.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List ) - post.Meta["embeds"] = new List>(); - var embeds = (List>)post.Meta["embeds"]; + post.Metadata["embeds"] = new List>(); + var embeds = (List>)post.Metadata["embeds"]; // Remove all old poll embeds embeds.RemoveAll(e => e.TryGetValue("type", out var type) && type.ToString() == "poll"); } @@ -681,19 +681,19 @@ public class PostActionController( return BadRequest("You can only share funds that you created."); var fundEmbed = new FundEmbed { Id = request.FundId.Value }; - post.Meta ??= new Dictionary(); + post.Metadata ??= new Dictionary(); if ( - !post.Meta.TryGetValue("embeds", out var existingEmbeds) + !post.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List ) - post.Meta["embeds"] = new List>(); - var embeds = (List>)post.Meta["embeds"]; + post.Metadata["embeds"] = new List>(); + var embeds = (List>)post.Metadata["embeds"]; // Remove all old fund embeds embeds.RemoveAll(e => e.TryGetValue("type", out var type) && type.ToString() == "fund" ); embeds.Add(EmbeddableBase.ToDictionary(fundEmbed)); - post.Meta["embeds"] = embeds; + post.Metadata["embeds"] = embeds; } catch (RpcException ex) when (ex.StatusCode == Grpc.Core.StatusCode.NotFound) { @@ -706,26 +706,26 @@ public class PostActionController( } else { - post.Meta ??= new Dictionary(); + post.Metadata ??= new Dictionary(); if ( - !post.Meta.TryGetValue("embeds", out var existingEmbeds) + !post.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List ) - post.Meta["embeds"] = new List>(); - var embeds = (List>)post.Meta["embeds"]; + post.Metadata["embeds"] = new List>(); + var embeds = (List>)post.Metadata["embeds"]; // Remove all old fund embeds embeds.RemoveAll(e => e.TryGetValue("type", out var type) && type.ToString() == "fund"); } if (request.ThumbnailId is not null) { - post.Meta ??= new Dictionary(); - post.Meta["thumbnail"] = request.ThumbnailId; + post.Metadata ??= new Dictionary(); + post.Metadata["thumbnail"] = request.ThumbnailId; } else { - post.Meta ??= new Dictionary(); - post.Meta.Remove("thumbnail"); + post.Metadata ??= new Dictionary(); + post.Metadata.Remove("thumbnail"); } // The realm is the same as well as the poll diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs index 1cdfec2..4e5beb3 100644 --- a/DysonNetwork.Sphere/Post/PostController.cs +++ b/DysonNetwork.Sphere/Post/PostController.cs @@ -336,7 +336,7 @@ public class PostController( .ToListAsync(); var accountsProto = await remoteAccountsHelper.GetAccountBatch( - reactions.Select(r => r.AccountId).ToList() + reactions.Where(r => r.AccountId.HasValue).Select(r => r.AccountId!.Value).ToList() ); var accounts = accountsProto.ToDictionary( a => Guid.Parse(a.Id), @@ -344,7 +344,7 @@ public class PostController( ); foreach (var reaction in reactions) - if (accounts.TryGetValue(reaction.AccountId, out var account)) + if (reaction.AccountId.HasValue && accounts.TryGetValue(reaction.AccountId.Value, out var account)) reaction.Account = account; return Ok(reactions); diff --git a/DysonNetwork.Sphere/Post/PostService.cs b/DysonNetwork.Sphere/Post/PostService.cs index 57cd4ce..0fcf808 100644 --- a/DysonNetwork.Sphere/Post/PostService.cs +++ b/DysonNetwork.Sphere/Post/PostService.cs @@ -170,7 +170,7 @@ public partial class PostService( var accounts = scope.ServiceProvider.GetRequiredService(); try { - var members = await pub.GetPublisherMembers(post.RepliedPost.PublisherId); + var members = await pub.GetPublisherMembers(post.RepliedPost.PublisherId!.Value); var queryRequest = new GetAccountBatchRequest(); queryRequest.Id.AddRange(members.Select(m => m.AccountId.ToString())); var queryResponse = await accounts.GetAccountBatchAsync(queryRequest); @@ -301,15 +301,10 @@ public partial class PostService( return item; // Initialize meta dictionary if null - item.Meta ??= new Dictionary(); - - // Initialize the embeds' array if it doesn't exist - if (!item.Meta.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List) - { - item.Meta["embeds"] = new List>(); - } - - var embeds = (List>)item.Meta["embeds"]; + item.Metadata ??= new Dictionary(); + if (!item.Metadata.TryGetValue("embeds", out var existingEmbeds) || existingEmbeds is not List) + item.Metadata["embeds"] = new List>(); + var embeds = (List>)item.Metadata["embeds"]; // Process up to 3 links to avoid excessive processing const int maxLinks = 3; @@ -340,13 +335,12 @@ public partial class PostService( } } - item.Meta["embeds"] = embeds; - + item.Metadata["embeds"] = embeds; return item; } /// - /// Process link previews for a post in the background + /// Process link previews for a post in background /// This method is designed to be called from a background task /// /// The post to process link previews for @@ -362,17 +356,17 @@ public partial class PostService( var updatedPost = await PreviewPostLinkAsync(post); // If embeds were added, update the post in the database - if (updatedPost.Meta != null && - updatedPost.Meta.TryGetValue("embeds", out var embeds) && + if (updatedPost.Metadata != null && + updatedPost.Metadata.TryGetValue("embeds", out var embeds) && embeds is List> { Count: > 0 } embedsList) { // Get a fresh copy of the post from the database var dbPost = await dbContext.Posts.FindAsync(post.Id); if (dbPost != null) { - // Update the meta field with the new embeds - dbPost.Meta ??= new Dictionary(); - dbPost.Meta["embeds"] = embedsList; + // Update the metadata field with the new embeds + dbPost.Metadata ??= new Dictionary(); + dbPost.Metadata["embeds"] = embedsList; // Save changes to the database dbContext.Update(dbPost); @@ -431,7 +425,7 @@ public partial class PostService( throw new InvalidOperationException("Replies can only be pinned in the reply page."); if (post.RepliedPost == null) throw new ArgumentNullException(nameof(post.RepliedPost)); - if (!await ps.IsMemberWithRole(post.RepliedPost.PublisherId, accountId, + if (!await ps.IsMemberWithRole(post.RepliedPost.PublisherId!.Value, accountId, Shared.Models.PublisherMemberRole.Editor)) throw new InvalidOperationException("Only editors of original post can pin replies."); @@ -439,7 +433,7 @@ public partial class PostService( } else { - if (!await ps.IsMemberWithRole(post.PublisherId, accountId, Shared.Models.PublisherMemberRole.Editor)) + if (post.PublisherId == null || !await ps.IsMemberWithRole(post.PublisherId.Value, accountId, Shared.Models.PublisherMemberRole.Editor)) throw new InvalidOperationException("Only editors can pin replies."); post.PinMode = pinMode; @@ -458,13 +452,13 @@ public partial class PostService( { if (post.RepliedPost == null) throw new ArgumentNullException(nameof(post.RepliedPost)); - if (!await ps.IsMemberWithRole(post.RepliedPost.PublisherId, accountId, + if (!await ps.IsMemberWithRole(post.RepliedPost.PublisherId!.Value, accountId, Shared.Models.PublisherMemberRole.Editor)) throw new InvalidOperationException("Only editors of original post can unpin replies."); } else { - if (!await ps.IsMemberWithRole(post.PublisherId, accountId, Shared.Models.PublisherMemberRole.Editor)) + if (post.PublisherId == null || !await ps.IsMemberWithRole(post.PublisherId.Value, accountId, Shared.Models.PublisherMemberRole.Editor)) throw new InvalidOperationException("Only editors can unpin posts."); } @@ -493,12 +487,14 @@ public partial class PostService( bool isSelfReact ) { - var isExistingReaction = await db.Set() - .AnyAsync(r => r.PostId == post.Id && r.AccountId == reaction.AccountId); + var isExistingReaction = reaction.AccountId.HasValue && + await db.Set() + .AnyAsync(r => r.PostId == post.Id && r.AccountId == reaction.AccountId.Value); if (isRemoving) await db.PostReactions - .Where(r => r.PostId == post.Id && r.Symbol == reaction.Symbol && r.AccountId == reaction.AccountId) + .Where(r => r.PostId == post.Id && r.Symbol == reaction.Symbol && + reaction.AccountId.HasValue && r.AccountId == reaction.AccountId.Value) .ExecuteDeleteAsync(); else db.PostReactions.Add(reaction); @@ -539,7 +535,8 @@ public partial class PostService( var accounts = scope.ServiceProvider.GetRequiredService(); try { - var members = await pub.GetPublisherMembers(post.PublisherId); + if (post.PublisherId == null) return; + var members = await pub.GetPublisherMembers(post.PublisherId.Value); var queryRequest = new GetAccountBatchRequest(); queryRequest.Id.AddRange(members.Select(m => m.AccountId.ToString())); var queryResponse = await accounts.GetAccountBatchAsync(queryRequest); @@ -675,15 +672,15 @@ public partial class PostService( foreach (var post in posts) { - if (publishers.TryGetValue(post.PublisherId, out var publisher)) + if (post.PublisherId.HasValue && publishers.TryGetValue(post.PublisherId.Value, out var publisher)) post.Publisher = publisher; if (post.RepliedPost?.PublisherId != null && - publishers.TryGetValue(post.RepliedPost.PublisherId, out var repliedPublisher)) + publishers.TryGetValue(post.RepliedPost.PublisherId.Value, out var repliedPublisher)) post.RepliedPost.Publisher = repliedPublisher; if (post.ForwardedPost?.PublisherId != null && - publishers.TryGetValue(post.ForwardedPost.PublisherId, out var forwardedPublisher)) + publishers.TryGetValue(post.ForwardedPost.PublisherId.Value, out var forwardedPublisher)) post.ForwardedPost.Publisher = forwardedPublisher; } @@ -780,7 +777,7 @@ public partial class PostService( // Check publication status - either published or user is member var isPublished = post.PublishedAt != null && now >= post.PublishedAt; - var isMember = publishersId.Contains(post.PublisherId); + var isMember = post.PublisherId.HasValue && publishersId.Contains(post.PublisherId.Value); if (!isPublished && !isMember) return false; @@ -967,7 +964,8 @@ public partial class PostService( { var sender = await accountsHelper.GetAccount(accountId); - var members = await pub.GetPublisherMembers(post.PublisherId); + if (post.PublisherId == null) return; + var members = await pub.GetPublisherMembers(post.PublisherId.Value); var queryRequest = new GetAccountBatchRequest(); queryRequest.Id.AddRange(members.Select(m => m.AccountId.ToString())); var queryResponse = await accounts.GetAccountBatchAsync(queryRequest); @@ -1021,7 +1019,7 @@ public static class PostQueryExtensions source = isListing switch { true when currentUser is not null => source.Where(e => - e.Visibility != Shared.Models.PostVisibility.Unlisted || publishersId.Contains(e.PublisherId)), + e.Visibility != Shared.Models.PostVisibility.Unlisted || (e.PublisherId.HasValue && publishersId.Contains(e.PublisherId.Value))), true => source.Where(e => e.Visibility != Shared.Models.PostVisibility.Unlisted), _ => source }; @@ -1032,10 +1030,10 @@ public static class PostQueryExtensions .Where(e => e.Visibility == Shared.Models.PostVisibility.Public); return source - .Where(e => (e.PublishedAt != null && now >= e.PublishedAt) || publishersId.Contains(e.PublisherId)) - .Where(e => e.Visibility != Shared.Models.PostVisibility.Private || publishersId.Contains(e.PublisherId)) + .Where(e => (e.PublishedAt != null && now >= e.PublishedAt) || (e.PublisherId.HasValue && publishersId.Contains(e.PublisherId.Value))) + .Where(e => e.Visibility != Shared.Models.PostVisibility.Private || publishersId.Contains(e.PublisherId.Value)) .Where(e => e.Visibility != Shared.Models.PostVisibility.Friends || (e.Publisher.AccountId != null && userFriends.Contains(e.Publisher.AccountId.Value)) || - publishersId.Contains(e.PublisherId)); + publishersId.Contains(e.PublisherId.Value)); } } diff --git a/DysonNetwork.Sphere/Publisher/PublisherService.cs b/DysonNetwork.Sphere/Publisher/PublisherService.cs index 34da815..618812a 100644 --- a/DysonNetwork.Sphere/Publisher/PublisherService.cs +++ b/DysonNetwork.Sphere/Publisher/PublisherService.cs @@ -556,9 +556,12 @@ public class PublisherService( .ToListAsync(); // Group stats by publisher id - var postIdToPublisher = postsInPeriod.ToDictionary(p => p.Id, p => p.PublisherId); + var postIdToPublisher = postsInPeriod + .Where(p => p.PublisherId.HasValue) + .ToDictionary(p => p.Id, p => p.PublisherId!.Value); var publisherStats = postsInPeriod - .GroupBy(p => p.PublisherId) + .Where(p => p.PublisherId.HasValue) + .GroupBy(p => p.PublisherId!.Value) .ToDictionary(g => g.Key, g => new { diff --git a/DysonNetwork.Sphere/Rewind/SphereRewindServiceGrpc.cs b/DysonNetwork.Sphere/Rewind/SphereRewindServiceGrpc.cs index 5250994..e11c6b4 100644 --- a/DysonNetwork.Sphere/Rewind/SphereRewindServiceGrpc.cs +++ b/DysonNetwork.Sphere/Rewind/SphereRewindServiceGrpc.cs @@ -33,7 +33,8 @@ public class SphereRewindServiceGrpc( var mostLovedPublisherClue = await db .PostReactions.Where(a => a.CreatedAt >= startDate && a.CreatedAt < endDate) .Where(p => p.AccountId == accountId && p.Attitude == PostReactionAttitude.Positive) - .GroupBy(p => p.Post.PublisherId) + .Where(p => p.Post.PublisherId.HasValue) + .GroupBy(p => p.Post.PublisherId!.Value) .OrderByDescending(g => g.Count()) .Select(g => new { PublisherId = g.Key, ReactionCount = g.Count() }) .FirstOrDefaultAsync(); @@ -51,9 +52,11 @@ public class SphereRewindServiceGrpc( .PostReactions.Where(a => a.CreatedAt >= startDate && a.CreatedAt < endDate) .Where(pr => pr.Attitude == PostReactionAttitude.Positive - && publishers.Contains(pr.Post.PublisherId) + && pr.AccountId.HasValue + && pr.Post.PublisherId.HasValue + && publishers.Contains(pr.Post.PublisherId.Value) ) - .GroupBy(pr => pr.AccountId) + .GroupBy(pr => pr.AccountId!.Value) .OrderByDescending(g => g.Count()) .Select(g => new { AccountId = g.Key, ReactionCount = g.Count() }) .FirstOrDefaultAsync(); @@ -63,12 +66,12 @@ public class SphereRewindServiceGrpc( var posts = db .Posts.Where(a => a.CreatedAt >= startDate && a.CreatedAt < endDate) - .Where(p => publishers.Contains(p.PublisherId)) + .Where(p => p.PublisherId.HasValue && publishers.Contains(p.PublisherId.Value)) .AsQueryable(); var postTotalCount = await posts.CountAsync(); var postTotalUpvotes = await db .PostReactions.Where(a => a.CreatedAt >= startDate && a.CreatedAt < endDate) - .Where(p => publishers.Contains(p.Post.PublisherId)) + .Where(p => p.Post.PublisherId.HasValue && publishers.Contains(p.Post.PublisherId.Value)) .Where(r => r.Attitude == PostReactionAttitude.Positive) .CountAsync(); var mostPopularPost = await posts diff --git a/DysonNetwork.Sphere/Timeline/TimelineService.cs b/DysonNetwork.Sphere/Timeline/TimelineService.cs index 543dad2..37c9cab 100644 --- a/DysonNetwork.Sphere/Timeline/TimelineService.cs +++ b/DysonNetwork.Sphere/Timeline/TimelineService.cs @@ -318,7 +318,7 @@ public class TimelineService( .AsQueryable(); if (filteredPublishersId != null && filteredPublishersId.Count != 0) - query = query.Where(p => filteredPublishersId.Contains(p.PublisherId)); + query = query.Where(p => p.PublisherId.HasValue && filteredPublishersId.Contains(p.PublisherId.Value)); if (userRealms == null) { // For anonymous users, only show public realm posts or posts without realm