From 086a12f971d62efd8c483a2fc926857d57860a8e Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 18 Jul 2025 12:20:47 +0800 Subject: [PATCH] :bug: Fix stuff I think --- DysonNetwork.Pass/Account/Account.cs | 90 +- .../Account/AccountServiceGrpc.cs | 1 + DysonNetwork.Pass/Account/Badge.cs | 47 +- DysonNetwork.Shared/Data/VerificationMark.cs | 22 + DysonNetwork.Shared/Proto/account.proto | 26 +- .../Registry/AccountClientHelper.cs | 21 + DysonNetwork.Shared/Registry/ServiceHelper.cs | 3 +- DysonNetwork.Sphere/Chat/ChatController.cs | 4 - DysonNetwork.Sphere/Chat/ChatRoom.cs | 2 +- .../Chat/ChatRoomController.cs | 28 +- DysonNetwork.Sphere/Chat/ChatRoomService.cs | 53 +- DysonNetwork.Sphere/Chat/ChatService.cs | 27 +- .../Chat/RealtimeCallController.cs | 2 - .../DysonNetwork.Sphere.csproj | 137 +- ...0250717135738_InitialMigration.Designer.cs | 1882 +++++++++++++++++ .../20250717135738_InitialMigration.cs | 1018 +++++++++ .../Migrations/AppDatabaseModelSnapshot.cs | 1879 ++++++++++++++++ DysonNetwork.Sphere/Program.cs | 1 - .../Publisher/PublisherController.cs | 2 - .../Realm/RealmController.cs.bak | 696 ------ .../Startup/ApplicationConfiguration.cs | 1 - .../Startup/ServiceCollectionExtensions.cs | 2 - DysonNetwork.Sphere/appsettings.json | 20 +- 23 files changed, 5114 insertions(+), 850 deletions(-) create mode 100644 DysonNetwork.Shared/Registry/AccountClientHelper.cs create mode 100644 DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.Designer.cs create mode 100644 DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.cs create mode 100644 DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs delete mode 100644 DysonNetwork.Sphere/Realm/RealmController.cs.bak diff --git a/DysonNetwork.Pass/Account/Account.cs b/DysonNetwork.Pass/Account/Account.cs index 6370e3c..c4f605a 100644 --- a/DysonNetwork.Pass/Account/Account.cs +++ b/DysonNetwork.Pass/Account/Account.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore; using NodaTime; using NodaTime.Serialization.Protobuf; using OtpNet; +using VerificationMark = DysonNetwork.Shared.Data.VerificationMark; namespace DysonNetwork.Pass.Account; @@ -41,7 +42,9 @@ public class Account : ModelBase Language = Language, ActivatedAt = ActivatedAt?.ToTimestamp(), IsSuperuser = IsSuperuser, - Profile = Profile.ToProtoValue() + Profile = Profile.ToProtoValue(), + CreatedAt = CreatedAt.ToTimestamp(), + UpdatedAt = UpdatedAt.ToTimestamp() }; // Add contacts @@ -54,6 +57,32 @@ public class Account : ModelBase return proto; } + + + public static Account FromProtoValue(Shared.Proto.Account proto) + { + var account = new Account + { + Id = Guid.Parse(proto.Id), + Name = proto.Name, + Nick = proto.Nick, + Language = proto.Language, + ActivatedAt = proto.ActivatedAt?.ToInstant(), + IsSuperuser = proto.IsSuperuser, + CreatedAt = proto.CreatedAt.ToInstant(), + UpdatedAt = proto.UpdatedAt.ToInstant(), + }; + + account.Profile = AccountProfile.FromProtoValue(proto.Profile); + + foreach (var contactProto in proto.Contacts) + account.Contacts.Add(AccountContact.FromProtoValue(contactProto)); + + foreach (var badgeProto in proto.Badges) + account.Badges.Add(AccountBadge.FromProtoValue(badgeProto)); + + return account; + } } public abstract class Leveling @@ -132,12 +161,42 @@ public class AccountProfile : ModelBase, IIdentifiedResource Background = Background?.ToProtoValue(), AccountId = AccountId.ToString(), Verification = Verification?.ToProtoValue(), - ActiveBadge = ActiveBadge?.ToProtoValue() + ActiveBadge = ActiveBadge?.ToProtoValue(), + CreatedAt = CreatedAt.ToTimestamp(), + UpdatedAt = UpdatedAt.ToTimestamp() }; return proto; } + public static AccountProfile FromProtoValue(Shared.Proto.AccountProfile proto) + { + var profile = new AccountProfile + { + Id = Guid.Parse(proto.Id), + FirstName = proto.FirstName, + LastName = proto.LastName, + MiddleName = proto.MiddleName, + Bio = proto.Bio, + Gender = proto.Gender, + Pronouns = proto.Pronouns, + TimeZone = proto.TimeZone, + Location = proto.Location, + Birthday = proto.Birthday?.ToInstant(), + LastSeenAt = proto.LastSeenAt?.ToInstant(), + Verification = proto.Verification is null ? null : VerificationMark.FromProtoValue(proto.Verification), + ActiveBadge = proto.ActiveBadge is null ? null : BadgeReferenceObject.FromProtoValue(proto.ActiveBadge), + Experience = proto.Experience, + Picture = proto.Picture is null ? null : CloudFileReferenceObject.FromProtoValue(proto.Picture), + Background = proto.Background is null ? null : CloudFileReferenceObject.FromProtoValue(proto.Background), + AccountId = Guid.Parse(proto.AccountId), + CreatedAt = proto.CreatedAt.ToInstant(), + UpdatedAt = proto.UpdatedAt.ToInstant() + }; + + return profile; + } + public string ResourceIdentifier => $"account:profile:{Id}"; } @@ -167,11 +226,36 @@ public class AccountContact : ModelBase Content = Content, IsPrimary = IsPrimary, VerifiedAt = VerifiedAt?.ToTimestamp(), - AccountId = AccountId.ToString() + AccountId = AccountId.ToString(), + CreatedAt = CreatedAt.ToTimestamp(), + UpdatedAt = UpdatedAt.ToTimestamp() }; return proto; } + + public static AccountContact FromProtoValue(Shared.Proto.AccountContact proto) + { + var contact = new AccountContact + { + Id = Guid.Parse(proto.Id), + AccountId = Guid.Parse(proto.AccountId), + Type = proto.Type switch + { + Shared.Proto.AccountContactType.Email => AccountContactType.Email, + Shared.Proto.AccountContactType.PhoneNumber => AccountContactType.PhoneNumber, + Shared.Proto.AccountContactType.Address => AccountContactType.Address, + _ => AccountContactType.Email + }, + Content = proto.Content, + IsPrimary = proto.IsPrimary, + VerifiedAt = proto.VerifiedAt?.ToInstant(), + CreatedAt = proto.CreatedAt.ToInstant(), + UpdatedAt = proto.UpdatedAt.ToInstant() + }; + + return contact; + } } public enum AccountContactType diff --git a/DysonNetwork.Pass/Account/AccountServiceGrpc.cs b/DysonNetwork.Pass/Account/AccountServiceGrpc.cs index 9402ef5..d7bda39 100644 --- a/DysonNetwork.Pass/Account/AccountServiceGrpc.cs +++ b/DysonNetwork.Pass/Account/AccountServiceGrpc.cs @@ -49,6 +49,7 @@ public class AccountServiceGrpc( var accounts = await _db.Accounts .AsNoTracking() .Where(a => accountIds.Contains(a.Id)) + .Include(a => a.Profile) .ToListAsync(); var response = new GetAccountBatchResponse(); diff --git a/DysonNetwork.Pass/Account/Badge.cs b/DysonNetwork.Pass/Account/Badge.cs index 8f61dcf..0e98bb6 100644 --- a/DysonNetwork.Pass/Account/Badge.cs +++ b/DysonNetwork.Pass/Account/Badge.cs @@ -15,7 +15,7 @@ public class AccountBadge : ModelBase [MaxLength(1024)] public string Type { get; set; } = null!; [MaxLength(1024)] public string? Label { get; set; } [MaxLength(4096)] public string? Caption { get; set; } - [Column(TypeName = "jsonb")] public Dictionary Meta { get; set; } = new(); + [Column(TypeName = "jsonb")] public Dictionary Meta { get; set; } = new(); public Instant? ActivatedAt { get; set; } public Instant? ExpiredAt { get; set; } @@ -33,7 +33,7 @@ public class AccountBadge : ModelBase Meta = Meta, ActivatedAt = ActivatedAt, ExpiredAt = ExpiredAt, - AccountId = AccountId + AccountId = AccountId, }; } @@ -48,11 +48,31 @@ public class AccountBadge : ModelBase ActivatedAt = ActivatedAt?.ToTimestamp(), ExpiredAt = ExpiredAt?.ToTimestamp(), AccountId = AccountId.ToString(), + CreatedAt = CreatedAt.ToTimestamp(), + UpdatedAt = UpdatedAt.ToTimestamp() }; proto.Meta.Add(GrpcTypeHelper.ConvertToValueMap(Meta)); return proto; } + + public static AccountBadge FromProtoValue(Shared.Proto.AccountBadge proto) + { + var badge = new AccountBadge + { + Id = Guid.Parse(proto.Id), + AccountId = Guid.Parse(proto.AccountId), + Type = proto.Type, + Label = proto.Label, + Caption = proto.Caption, + ActivatedAt = proto.ActivatedAt?.ToInstant(), + ExpiredAt = proto.ExpiredAt?.ToInstant(), + CreatedAt = proto.CreatedAt.ToInstant(), + UpdatedAt = proto.UpdatedAt.ToInstant() + }; + + return badge; + } } public class BadgeReferenceObject : ModelBase @@ -61,7 +81,7 @@ public class BadgeReferenceObject : ModelBase public string Type { get; set; } = null!; public string? Label { get; set; } public string? Caption { get; set; } - public Dictionary? Meta { get; set; } + public Dictionary Meta { get; set; } public Instant? ActivatedAt { get; set; } public Instant? ExpiredAt { get; set; } public Guid AccountId { get; set; } @@ -78,9 +98,26 @@ public class BadgeReferenceObject : ModelBase ExpiredAt = ExpiredAt?.ToTimestamp(), AccountId = AccountId.ToString() }; - if (Meta is not null) - proto.Meta.Add(GrpcTypeHelper.ConvertToValueMap(Meta!)); + proto.Meta.Add(GrpcTypeHelper.ConvertToValueMap(Meta!)); return proto; } + + + public static BadgeReferenceObject FromProtoValue(Shared.Proto.BadgeReferenceObject proto) + { + var badge = new BadgeReferenceObject + { + Id = Guid.Parse(proto.Id), + Type = proto.Type, + Label = proto.Label, + Caption = proto.Caption, + Meta = GrpcTypeHelper.ConvertFromValueMap(proto.Meta).ToDictionary(), + ActivatedAt = proto.ActivatedAt?.ToInstant(), + ExpiredAt = proto.ExpiredAt?.ToInstant(), + AccountId = Guid.Parse(proto.AccountId) + }; + + return badge; + } } \ No newline at end of file diff --git a/DysonNetwork.Shared/Data/VerificationMark.cs b/DysonNetwork.Shared/Data/VerificationMark.cs index f22febd..45eb071 100644 --- a/DysonNetwork.Shared/Data/VerificationMark.cs +++ b/DysonNetwork.Shared/Data/VerificationMark.cs @@ -36,6 +36,28 @@ public class VerificationMark return proto; } + + + public static VerificationMark FromProtoValue(Shared.Proto.VerificationMark proto) + { + return new VerificationMark + { + Type = proto.Type switch + { + Proto.VerificationMarkType.Official => VerificationMarkType.Official, + Proto.VerificationMarkType.Individual => VerificationMarkType.Individual, + Proto.VerificationMarkType.Organization => VerificationMarkType.Organization, + Proto.VerificationMarkType.Government => VerificationMarkType.Government, + Proto.VerificationMarkType.Creator => VerificationMarkType.Creator, + Proto.VerificationMarkType.Developer => VerificationMarkType.Developer, + Proto.VerificationMarkType.Parody => VerificationMarkType.Parody, + _ => VerificationMarkType.Individual + }, + Title = proto.Title, + Description = proto.Description, + VerifiedBy = proto.VerifiedBy + }; + } } public enum VerificationMarkType diff --git a/DysonNetwork.Shared/Proto/account.proto b/DysonNetwork.Shared/Proto/account.proto index 1a2a0cb..bad0af4 100644 --- a/DysonNetwork.Shared/Proto/account.proto +++ b/DysonNetwork.Shared/Proto/account.proto @@ -6,7 +6,6 @@ option csharp_namespace = "DysonNetwork.Shared.Proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; -import "google/protobuf/empty.proto"; import "google/protobuf/field_mask.proto"; import "google/protobuf/struct.proto"; @@ -28,6 +27,9 @@ message Account { repeated AccountConnection connections = 11; repeated Relationship outgoing_relationships = 12; repeated Relationship incoming_relationships = 13; + + google.protobuf.Timestamp created_at = 14; + google.protobuf.Timestamp updated_at = 15; } // Profile contains detailed information about a user @@ -55,6 +57,9 @@ message AccountProfile { CloudFile background = 20; string account_id = 21; + + google.protobuf.Timestamp created_at = 22; + google.protobuf.Timestamp updated_at = 23; } // AccountContact represents a contact method for an account @@ -65,6 +70,9 @@ message AccountContact { bool is_primary = 4; string content = 5; string account_id = 6; + + google.protobuf.Timestamp created_at = 7; + google.protobuf.Timestamp updated_at = 8; } // Enum for contact types @@ -85,7 +93,10 @@ message AccountAuthFactor { google.protobuf.Timestamp enabled_at = 6; google.protobuf.Timestamp expired_at = 7; string account_id = 8; - map created_response = 9; // For initial setup + map created_response = 9; // For initial setup + + google.protobuf.Timestamp created_at = 10; + google.protobuf.Timestamp updated_at = 11; } // Enum for authentication factor types @@ -108,6 +119,9 @@ message AccountBadge { google.protobuf.Timestamp activated_at = 6; // When the badge was activated google.protobuf.Timestamp expired_at = 7; // Optional expiration time string account_id = 8; // ID of the account this badge belongs to + + google.protobuf.Timestamp created_at = 9; + google.protobuf.Timestamp updated_at = 10; } // AccountConnection represents a third-party connection for an account @@ -120,6 +134,9 @@ message AccountConnection { google.protobuf.StringValue refresh_token = 6; // Omitted from JSON serialization google.protobuf.Timestamp last_used_at = 7; string account_id = 8; + + google.protobuf.Timestamp created_at = 9; + google.protobuf.Timestamp updated_at = 10; } // VerificationMark represents verification status @@ -128,6 +145,9 @@ message VerificationMark { string title = 2; string description = 3; string verified_by = 4; + + google.protobuf.Timestamp created_at = 5; + google.protobuf.Timestamp updated_at = 6; } enum VerificationMarkType { @@ -160,6 +180,7 @@ message Relationship { optional Account account = 3; optional Account related = 4; int32 status = 5; + google.protobuf.Timestamp created_at = 6; google.protobuf.Timestamp updated_at = 7; } @@ -184,6 +205,7 @@ message ActionLog { google.protobuf.StringValue location = 6; // Geographic location of the client, derived from IP string account_id = 7; // The account that performed the action google.protobuf.StringValue session_id = 8; // The session in which the action was performed + google.protobuf.Timestamp created_at = 9; // When the action log was created } diff --git a/DysonNetwork.Shared/Registry/AccountClientHelper.cs b/DysonNetwork.Shared/Registry/AccountClientHelper.cs new file mode 100644 index 0000000..977eab7 --- /dev/null +++ b/DysonNetwork.Shared/Registry/AccountClientHelper.cs @@ -0,0 +1,21 @@ +using DysonNetwork.Shared.Proto; + +namespace DysonNetwork.Shared.Registry; + +public class AccountClientHelper(AccountService.AccountServiceClient accounts) +{ + public async Task GetAccount(Guid id) + { + var request = new GetAccountRequest { Id = id.ToString() }; + var response = await accounts.GetAccountAsync(request); + return response; + } + + public async Task> GetAccountBatch(List ids) + { + var request = new GetAccountBatchRequest(); + request.Id.AddRange(ids.Select(id => id.ToString())); + var response = await accounts.GetAccountBatchAsync(request); + return response.Accounts.ToList(); + } +} \ No newline at end of file diff --git a/DysonNetwork.Shared/Registry/ServiceHelper.cs b/DysonNetwork.Shared/Registry/ServiceHelper.cs index d30576f..6ae2adc 100644 --- a/DysonNetwork.Shared/Registry/ServiceHelper.cs +++ b/DysonNetwork.Shared/Registry/ServiceHelper.cs @@ -40,7 +40,8 @@ public static class ServiceHelper .CreateAccountServiceClient(etcdClient, clientCertPath, clientKeyPath, clientCertPassword) .GetAwaiter() .GetResult(); - }); + }); + services.AddSingleton(); services.AddSingleton(sp => { diff --git a/DysonNetwork.Sphere/Chat/ChatController.cs b/DysonNetwork.Sphere/Chat/ChatController.cs index ee54c05..7429e5f 100644 --- a/DysonNetwork.Sphere/Chat/ChatController.cs +++ b/DysonNetwork.Sphere/Chat/ChatController.cs @@ -97,8 +97,6 @@ public partial class ChatController( .Where(m => m.ChatRoomId == roomId) .OrderByDescending(m => m.CreatedAt) .Include(m => m.Sender) - .Include(m => m.Sender.Account) - .Include(m => m.Sender.Account.Profile) .Skip(offset) .Take(take) .ToListAsync(); @@ -232,8 +230,6 @@ public partial class ChatController( var message = await db.ChatMessages .Include(m => m.Sender) - .Include(m => m.Sender.Account) - .Include(m => m.Sender.Account.Profile) .Include(message => message.ChatRoom) .FirstOrDefaultAsync(m => m.Id == messageId && m.ChatRoomId == roomId); diff --git a/DysonNetwork.Sphere/Chat/ChatRoom.cs b/DysonNetwork.Sphere/Chat/ChatRoom.cs index 6322029..44f0fd7 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoom.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoom.cs @@ -2,8 +2,8 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; using DysonNetwork.Shared.Data; -using DysonNetwork.Shared.Proto; using NodaTime; +using Account = DysonNetwork.Pass.Account.Account; namespace DysonNetwork.Sphere.Chat; diff --git a/DysonNetwork.Sphere/Chat/ChatRoomController.cs b/DysonNetwork.Sphere/Chat/ChatRoomController.cs index 23535cc..17d4690 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomController.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomController.cs @@ -194,7 +194,7 @@ public class ChatRoomController( { Role = ChatMemberRole.Owner, AccountId = Guid.Parse(currentUser.Id), - JoinedAt = NodaTime.Instant.FromDateTimeUtc(DateTime.UtcNow) + JoinedAt = Instant.FromDateTimeUtc(DateTime.UtcNow) } } }; @@ -452,21 +452,23 @@ public class ChatRoomController( var member = await db.ChatMembers .Where(m => m.AccountId == Guid.Parse(currentUser.Id) && m.ChatRoomId == roomId) - .Include(m => m.Account) - .Include(m => m.Account.Profile) .FirstOrDefaultAsync(); if (member == null) return NotFound(); - return Ok(member); + return Ok(await crs.LoadMemberAccount(member)); } [HttpGet("{roomId:guid}/members")] - public async Task>> ListMembers(Guid roomId, [FromQuery] int take = 20, - [FromQuery] int skip = 0, [FromQuery] bool withStatus = false, [FromQuery] string? status = null) + public async Task>> ListMembers(Guid roomId, + [FromQuery] int take = 20, + [FromQuery] int skip = 0, + [FromQuery] bool withStatus = false, + [FromQuery] string? status = null + ) { - var currentUser = HttpContext.Items["CurrentUser"] as Shared.Proto.Account; + var currentUser = HttpContext.Items["CurrentUser"] as Account; var room = await db.ChatRooms .FirstOrDefaultAsync(r => r.Id == roomId); @@ -480,11 +482,9 @@ public class ChatRoomController( if (member is null) return StatusCode(403, "You need to be a member to see members of private chat room."); } - IQueryable query = db.ChatMembers + var query = db.ChatMembers .Where(m => m.ChatRoomId == roomId) - .Where(m => m.LeaveAt == null) // Add this condition to exclude left members - .Include(m => m.Account) - .Include(m => m.Account.Profile); + .Where(m => m.LeaveAt == null); // if (withStatus) // { @@ -509,7 +509,7 @@ public class ChatRoomController( // // var result = members.Skip(skip).Take(take).ToList(); // - // return Ok(result); + // return Ok(await crs.LoadMemberAccounts(result)); // } // else // { @@ -522,7 +522,7 @@ public class ChatRoomController( .Take(take) .ToListAsync(); - return Ok(members); + return Ok(await crs.LoadMemberAccounts(members)); // } } @@ -952,7 +952,7 @@ public class ChatRoomController( ? localizer["ChatInviteDirectBody", sender.Nick] : localizer["ChatInviteBody", member.ChatRoom.Name ?? "Unnamed"]; - CultureService.SetCultureInfo(member.Account); + CultureService.SetCultureInfo(member.Account.Language); await pusher.SendPushNotificationToUserAsync( new SendPushNotificationToUserRequest { diff --git a/DysonNetwork.Sphere/Chat/ChatRoomService.cs b/DysonNetwork.Sphere/Chat/ChatRoomService.cs index 1e23d19..aec8e5b 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomService.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomService.cs @@ -1,12 +1,18 @@ using DysonNetwork.Shared.Cache; +using DysonNetwork.Shared.Registry; using Microsoft.EntityFrameworkCore; using NodaTime; +using Account = DysonNetwork.Pass.Account.Account; namespace DysonNetwork.Sphere.Chat; -public class ChatRoomService(AppDatabase db, ICacheService cache) +public class ChatRoomService( + AppDatabase db, + ICacheService cache, + AccountClientHelper accountsHelper +) { - public const string ChatRoomGroupPrefix = "chatroom:"; + private const string ChatRoomGroupPrefix = "chatroom:"; private const string RoomMembersCacheKeyPrefix = "chatroom:members:"; private const string ChatMemberCacheKey = "chatroom:{0}:member:{1}"; @@ -18,12 +24,11 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) return cachedMembers; var members = await db.ChatMembers - .Include(m => m.Account) - .ThenInclude(m => m.Profile) .Where(m => m.ChatRoomId == roomId) .Where(m => m.JoinedAt != null) .Where(m => m.LeaveAt == null) .ToListAsync(); + members = await LoadMemberAccounts(members); var chatRoomGroup = ChatRoomGroupPrefix + roomId; await cache.SetWithGroupsAsync(cacheKey, members, @@ -40,14 +45,13 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) if (member is not null) return member; member = await db.ChatMembers - .Include(m => m.Account) - .ThenInclude(m => m.Profile) - .Include(m => m.ChatRoom) - .ThenInclude(m => m.Realm) .Where(m => m.AccountId == accountId && m.ChatRoomId == chatRoomId) + .Include(m => m.ChatRoom) .FirstOrDefaultAsync(); - + if (member == null) return member; + + member = await LoadMemberAccount(member); var chatRoomGroup = ChatRoomGroupPrefix + chatRoomId; await cache.SetWithGroupsAsync(cacheKey, member, [chatRoomGroup], @@ -92,8 +96,6 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) .Where(m => directRoomsId.Contains(m.ChatRoomId)) .Where(m => m.AccountId != userId) .Where(m => m.LeaveAt == null) - .Include(m => m.Account) - .Include(m => m.Account.Profile) .GroupBy(m => m.ChatRoomId) .ToDictionaryAsync(g => g.Key, g => g.ToList()) : new Dictionary>(); @@ -112,12 +114,13 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) var members = await db.ChatMembers .Where(m => m.ChatRoomId == room.Id && m.AccountId != userId) .Where(m => m.LeaveAt == null) - .Include(m => m.Account) - .Include(m => m.Account.Profile) .ToListAsync(); - if (members.Count > 0) - room.DirectMembers = members.Select(ChatMemberTransmissionObject.FromEntity).ToList(); + if (members.Count <= 0) return room; + + members = await LoadMemberAccounts(members); + room.DirectMembers = members.Select(ChatMemberTransmissionObject.FromEntity).ToList(); + return room; } @@ -131,4 +134,24 @@ public class ChatRoomService(AppDatabase db, ICacheService cache) .FirstOrDefaultAsync(m => m.ChatRoomId == roomId && m.AccountId == accountId); return member?.Role >= maxRequiredRole; } + + public async Task LoadMemberAccount(ChatMember member) + { + var account = await accountsHelper.GetAccount(member.AccountId); + member.Account = Account.FromProtoValue(account); + return member; + } + + public async Task> LoadMemberAccounts(ICollection members) + { + var accountIds = members.Select(m => m.AccountId).ToList(); + var accounts = (await accountsHelper.GetAccountBatch(accountIds)).ToDictionary(a => Guid.Parse(a.Id), a => a); + + return members.Select(m => + { + if (accounts.TryGetValue(m.AccountId, out var account)) + m.Account = Account.FromProtoValue(account); + return m; + }).ToList(); + } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Chat/ChatService.cs b/DysonNetwork.Sphere/Chat/ChatService.cs index 465297e..c6a5ec3 100644 --- a/DysonNetwork.Sphere/Chat/ChatService.cs +++ b/DysonNetwork.Sphere/Chat/ChatService.cs @@ -9,6 +9,7 @@ namespace DysonNetwork.Sphere.Chat; public partial class ChatService( AppDatabase db, + ChatRoomService crs, FileService.FileServiceClient filesClient, FileReferenceService.FileReferenceServiceClient fileRefs, IServiceScopeFactory scopeFactory, @@ -259,7 +260,7 @@ public partial class ChatService( } else if (member.Notify == ChatMemberNotify.Mentions) continue; - accountsToNotify.Add(member.Account); + accountsToNotify.Add(member.Account.ToProtoValue()); } logger.LogInformation($"Trying to deliver message to {accountsToNotify.Count} accounts..."); @@ -333,8 +334,6 @@ public partial class ChatService( var messages = await db.ChatMessages .IgnoreQueryFilters() .Include(m => m.Sender) - .Include(m => m.Sender.Account) - .Include(m => m.Sender.Account.Profile) .Where(m => userRooms.Contains(m.ChatRoomId)) .GroupBy(m => m.ChatRoomId) .Select(g => g.OrderByDescending(m => m.CreatedAt).FirstOrDefault()) @@ -450,8 +449,6 @@ public partial class ChatService( var changes = await db.ChatMessages .IgnoreQueryFilters() .Include(e => e.Sender) - .Include(e => e.Sender.Account) - .Include(e => e.Sender.Account.Profile) .Where(m => m.ChatRoomId == roomId) .Where(m => m.UpdatedAt > timestamp || m.DeletedAt > timestamp) .Select(m => new MessageChange @@ -463,6 +460,20 @@ public partial class ChatService( }) .ToListAsync(); + var changesMembers = changes + .Select(c => c.Message!.Sender) + .DistinctBy(x => x.Id) + .ToList(); + changesMembers = await crs.LoadMemberAccounts(changesMembers); + + foreach (var change in changes) + { + if (change.Message == null) continue; + var sender = changesMembers.FirstOrDefault(x => x.Id == change.Message.SenderId); + if (sender is not null) + change.Message.Sender = sender; + } + return new SyncResponse { Changes = changes, @@ -493,18 +504,16 @@ public partial class ChatService( if (attachmentsId is not null) { - var messageResourceId = $"message:{message.Id}"; - // Delete existing references for this message await fileRefs.DeleteResourceReferencesAsync( - new DeleteResourceReferencesRequest { ResourceId = messageResourceId } + new DeleteResourceReferencesRequest { ResourceId = message.ResourceIdentifier } ); // Create new references for each attachment var createRequest = new CreateReferenceBatchRequest { Usage = ChatFileUsageIdentifier, - ResourceId = messageResourceId, + ResourceId = message.ResourceIdentifier, }; createRequest.FilesId.AddRange(attachmentsId); await fileRefs.CreateReferenceBatchAsync(createRequest); diff --git a/DysonNetwork.Sphere/Chat/RealtimeCallController.cs b/DysonNetwork.Sphere/Chat/RealtimeCallController.cs index 998b9a5..274fd58 100644 --- a/DysonNetwork.Sphere/Chat/RealtimeCallController.cs +++ b/DysonNetwork.Sphere/Chat/RealtimeCallController.cs @@ -62,8 +62,6 @@ public class RealtimeCallController( .Where(c => c.EndedAt == null) .Include(c => c.Room) .Include(c => c.Sender) - .ThenInclude(c => c.Account) - .ThenInclude(c => c.Profile) .FirstOrDefaultAsync(); if (ongoingCall is null) return NotFound(); return Ok(ongoingCall); diff --git a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj index ccf0734..119a556 100644 --- a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj +++ b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj @@ -16,70 +16,55 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -89,8 +74,7 @@ - - + @@ -157,31 +141,32 @@ True NotificationResource.resx - + - <_ContentIncludedByDefault Remove="app\publish\appsettings.json" /> - <_ContentIncludedByDefault Remove="app\publish\DysonNetwork.Sphere.deps.json" /> - <_ContentIncludedByDefault Remove="app\publish\DysonNetwork.Sphere.runtimeconfig.json" /> - <_ContentIncludedByDefault Remove="app\publish\DysonNetwork.Sphere.staticwebassets.endpoints.json" /> - <_ContentIncludedByDefault Remove="app\publish\Keys\Solian.json" /> - <_ContentIncludedByDefault Remove="app\publish\package-lock.json" /> - <_ContentIncludedByDefault Remove="app\publish\package.json" /> - <_ContentIncludedByDefault Remove="Pages\Account\Profile.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Auth\Authorize.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Auth\Callback.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Auth\Challenge.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Auth\Login.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Auth\SelectFactor.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Auth\VerifyFactor.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Checkpoint\CheckpointPage.cshtml" /> - <_ContentIncludedByDefault Remove="Pages\Spell\MagicSpellPage.cshtml" /> - <_ContentIncludedByDefault Remove="Keys\Solian.json" /> + <_ContentIncludedByDefault Remove="app\publish\appsettings.json"/> + <_ContentIncludedByDefault Remove="app\publish\DysonNetwork.Sphere.deps.json"/> + <_ContentIncludedByDefault Remove="app\publish\DysonNetwork.Sphere.runtimeconfig.json"/> + <_ContentIncludedByDefault Remove="app\publish\DysonNetwork.Sphere.staticwebassets.endpoints.json"/> + <_ContentIncludedByDefault Remove="app\publish\Keys\Solian.json"/> + <_ContentIncludedByDefault Remove="app\publish\package-lock.json"/> + <_ContentIncludedByDefault Remove="app\publish\package.json"/> + <_ContentIncludedByDefault Remove="Pages\Account\Profile.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Auth\Authorize.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Auth\Callback.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Auth\Challenge.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Auth\Login.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Auth\SelectFactor.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Auth\VerifyFactor.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Checkpoint\CheckpointPage.cshtml"/> + <_ContentIncludedByDefault Remove="Pages\Spell\MagicSpellPage.cshtml"/> + <_ContentIncludedByDefault Remove="Keys\Solian.json"/> - + + diff --git a/DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.Designer.cs b/DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.Designer.cs new file mode 100644 index 0000000..b59b1b8 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.Designer.cs @@ -0,0 +1,1882 @@ +// +using System; +using System.Collections.Generic; +using DysonNetwork.Shared.Data; +using DysonNetwork.Sphere; +using DysonNetwork.Sphere.Chat; +using DysonNetwork.Sphere.Developer; +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; +using NpgsqlTypes; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + [DbContext(typeof(AppDatabase))] + [Migration("20250717135738_InitialMigration")] + partial class InitialMigration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatMember", 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("IsBot") + .HasColumnType("boolean") + .HasColumnName("is_bot"); + + 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("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + 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.ToTable("chat_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Background") + .HasColumnType("jsonb") + .HasColumnName("background"); + + b.Property("BackgroundId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("background_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("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("PictureId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("picture_id"); + + 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.HasIndex("RealmId") + .HasDatabaseName("ix_chat_rooms_realm_id"); + + b.ToTable("chat_rooms", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", 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.Property>("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.Sphere.Chat.MessageReaction", 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.Sphere.Chat.RealtimeCall", 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.Sphere.Developer.CustomApp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("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("Links") + .HasColumnType("jsonb") + .HasColumnName("links"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("OauthConfig") + .HasColumnType("jsonb") + .HasColumnName("oauth_config"); + + b.Property("Picture") + .HasColumnType("jsonb") + .HasColumnName("picture"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("slug"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Verification") + .HasColumnType("jsonb") + .HasColumnName("verification"); + + b.HasKey("Id") + .HasName("pk_custom_apps"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_custom_apps_publisher_id"); + + b.ToTable("custom_apps", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomAppSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_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("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("IsOidc") + .HasColumnType("boolean") + .HasColumnName("is_oidc"); + + b.Property("Secret") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("secret"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_custom_app_secrets"); + + b.HasIndex("AppId") + .HasDatabaseName("ix_custom_app_secrets_app_id"); + + b.HasIndex("Secret") + .IsUnique() + .HasDatabaseName("ix_custom_app_secrets_secret"); + + b.ToTable("custom_app_secrets", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property>("Attachments") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("attachments"); + + 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("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("ForwardedPostId") + .HasColumnType("uuid") + .HasColumnName("forwarded_post_id"); + + b.Property("Language") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("language"); + + b.Property>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("PublishedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("published_at"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("RepliedPostId") + .HasColumnType("uuid") + .HasColumnName("replied_post_id"); + + b.Property("SearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("tsvector") + .HasColumnName("search_vector") + .HasAnnotation("Npgsql:TsVectorConfig", "simple") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "Title", "Description", "Content" }); + + b.Property>("SensitiveMarks") + .HasColumnType("jsonb") + .HasColumnName("sensitive_marks"); + + 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("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.HasIndex("SearchVector") + .HasDatabaseName("ix_posts_search_vector"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("SearchVector"), "GIN"); + + b.ToTable("posts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCategory", 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.Sphere.Post.PostCollection", 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.Sphere.Post.PostReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_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("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("PostId") + .HasDatabaseName("ix_post_reactions_post_id"); + + b.ToTable("post_reactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostTag", 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.Sphere.Publisher.Publisher", 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("BackgroundId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("background_id"); + + 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("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("PictureId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("picture_id"); + + 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.HasIndex("RealmId") + .HasDatabaseName("ix_publishers_realm_id"); + + b.ToTable("publishers", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherFeature", 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.Sphere.Publisher.PublisherMember", 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.Sphere.Publisher.PublisherSubscription", 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.Sphere.Realm.Realm", 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("BackgroundId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("background_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("IsCommunity") + .HasColumnType("boolean") + .HasColumnName("is_community"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("is_public"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("Picture") + .HasColumnType("jsonb") + .HasColumnName("picture"); + + b.Property("PictureId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("picture_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Verification") + .HasColumnType("jsonb") + .HasColumnName("verification"); + + b.HasKey("Id") + .HasName("pk_realms"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_realms_slug"); + + b.ToTable("realms", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b => + { + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_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("LeaveAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("leave_at"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("RealmId", "AccountId") + .HasName("pk_realm_members"); + + b.ToTable("realm_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmTag", b => + { + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_id"); + + b.Property("TagId") + .HasColumnType("uuid") + .HasColumnName("tag_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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("RealmId", "TagId") + .HasName("pk_realm_tags"); + + b.HasIndex("TagId") + .HasDatabaseName("ix_realm_tags_tag_id"); + + b.ToTable("realm_tags", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Tag", 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") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("name"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_tags"); + + b.ToTable("tags", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", 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") + .HasColumnType("jsonb") + .HasColumnName("image"); + + b.Property("ImageId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("image_id"); + + 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.Sphere.Sticker.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("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.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("PostPostCategory", 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("PostPostCollection", 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("PostPostTag", 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.Sphere.Chat.ChatMember", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "ChatRoom") + .WithMany("Members") + .HasForeignKey("ChatRoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_members_chat_rooms_chat_room_id"); + + b.Navigation("ChatRoom"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("ChatRooms") + .HasForeignKey("RealmId") + .HasConstraintName("fk_chat_rooms_realms_realm_id"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "ChatRoom") + .WithMany() + .HasForeignKey("ChatRoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_messages_chat_rooms_chat_room_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.Message", "ForwardedMessage") + .WithMany() + .HasForeignKey("ForwardedMessageId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_chat_messages_chat_messages_forwarded_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.Message", "RepliedMessage") + .WithMany() + .HasForeignKey("RepliedMessageId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_chat_messages_chat_messages_replied_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "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.Sphere.Chat.MessageReaction", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.Message", "Message") + .WithMany("Reactions") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_reactions_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "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.Sphere.Chat.RealtimeCall", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "Room") + .WithMany() + .HasForeignKey("RoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_realtime_call_chat_rooms_room_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "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.Sphere.Developer.CustomApp", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Developer") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_custom_apps_publishers_publisher_id"); + + b.Navigation("Developer"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomAppSecret", b => + { + b.HasOne("DysonNetwork.Sphere.Developer.CustomApp", "App") + .WithMany("Secrets") + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_custom_app_secrets_custom_apps_app_id"); + + b.Navigation("App"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Post", "ForwardedPost") + .WithMany() + .HasForeignKey("ForwardedPostId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_posts_posts_forwarded_post_id"); + + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Posts") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_posts_publishers_publisher_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", "RepliedPost") + .WithMany() + .HasForeignKey("RepliedPostId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_posts_posts_replied_post_id"); + + b.Navigation("ForwardedPost"); + + b.Navigation("Publisher"); + + b.Navigation("RepliedPost"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Collections") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collections_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostReaction", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Post", "Post") + .WithMany("Reactions") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_posts_post_id"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany() + .HasForeignKey("RealmId") + .HasConstraintName("fk_publishers_realms_realm_id"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherFeature", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Features") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_features_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherMember", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Members") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Subscriptions") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("Members") + .HasForeignKey("RealmId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_members_realms_realm_id"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmTag", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("RealmTags") + .HasForeignKey("RealmId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_tags_realms_realm_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Tag", "Tag") + .WithMany("RealmTags") + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_tags_tags_tag_id"); + + b.Navigation("Realm"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b => + { + b.HasOne("DysonNetwork.Sphere.Sticker.StickerPack", "Pack") + .WithMany() + .HasForeignKey("PackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_sticker_packs_pack_id"); + + b.Navigation("Pack"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.StickerPack", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_sticker_packs_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + 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.Sphere.Publisher.Publisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_web_feeds_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("PostPostCategory", b => + { + b.HasOne("DysonNetwork.Sphere.Post.PostCategory", null) + .WithMany() + .HasForeignKey("CategoriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_category_links_post_categories_categories_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_category_links_posts_posts_id"); + }); + + modelBuilder.Entity("PostPostCollection", b => + { + b.HasOne("DysonNetwork.Sphere.Post.PostCollection", null) + .WithMany() + .HasForeignKey("CollectionsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collection_links_post_collections_collections_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collection_links_posts_posts_id"); + }); + + modelBuilder.Entity("PostPostTag", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_tag_links_posts_posts_id"); + + b.HasOne("DysonNetwork.Sphere.Post.PostTag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_tag_links_post_tags_tags_id"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", b => + { + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomApp", b => + { + b.Navigation("Secrets"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => + { + b.Navigation("Collections"); + + b.Navigation("Features"); + + b.Navigation("Members"); + + b.Navigation("Posts"); + + b.Navigation("Subscriptions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b => + { + b.Navigation("ChatRooms"); + + b.Navigation("Members"); + + b.Navigation("RealmTags"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Tag", b => + { + b.Navigation("RealmTags"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeed", b => + { + b.Navigation("Articles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.cs b/DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.cs new file mode 100644 index 0000000..03f39bb --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250717135738_InitialMigration.cs @@ -0,0 +1,1018 @@ +using System; +using System.Collections.Generic; +using DysonNetwork.Shared.Data; +using DysonNetwork.Sphere.Chat; +using DysonNetwork.Sphere.Developer; +using DysonNetwork.Sphere.WebReader; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; +using NpgsqlTypes; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + /// + public partial class InitialMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterDatabase() + .Annotation("Npgsql:PostgresExtension:postgis", ",,"); + + migrationBuilder.CreateTable( + name: "post_categories", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_categories", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "post_tags", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_tags", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "realms", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + slug = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), + is_community = table.Column(type: "boolean", nullable: false), + is_public = table.Column(type: "boolean", nullable: false), + picture_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + background_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + picture = table.Column(type: "jsonb", nullable: true), + background = table.Column(type: "jsonb", nullable: true), + verification = table.Column(type: "jsonb", nullable: true), + account_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_realms", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "tags", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + name = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_tags", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "chat_rooms", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + type = table.Column(type: "integer", nullable: false), + is_community = table.Column(type: "boolean", nullable: false), + is_public = table.Column(type: "boolean", nullable: false), + picture_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + background_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + picture = table.Column(type: "jsonb", nullable: true), + background = table.Column(type: "jsonb", nullable: true), + realm_id = table.Column(type: "uuid", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_chat_rooms", x => x.id); + table.ForeignKey( + name: "fk_chat_rooms_realms_realm_id", + column: x => x.realm_id, + principalTable: "realms", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "publishers", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + type = table.Column(type: "integer", nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + nick = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + bio = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + picture_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + background_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + picture = table.Column(type: "jsonb", nullable: true), + background = table.Column(type: "jsonb", nullable: true), + verification = table.Column(type: "jsonb", nullable: true), + account_id = table.Column(type: "uuid", nullable: true), + realm_id = table.Column(type: "uuid", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_publishers", x => x.id); + table.ForeignKey( + name: "fk_publishers_realms_realm_id", + column: x => x.realm_id, + principalTable: "realms", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "realm_members", + columns: table => new + { + realm_id = table.Column(type: "uuid", nullable: false), + account_id = table.Column(type: "uuid", nullable: false), + role = table.Column(type: "integer", nullable: false), + joined_at = table.Column(type: "timestamp with time zone", nullable: true), + leave_at = table.Column(type: "timestamp with time zone", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_realm_members", x => new { x.realm_id, x.account_id }); + table.ForeignKey( + name: "fk_realm_members_realms_realm_id", + column: x => x.realm_id, + principalTable: "realms", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "realm_tags", + columns: table => new + { + realm_id = table.Column(type: "uuid", nullable: false), + tag_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_realm_tags", x => new { x.realm_id, x.tag_id }); + table.ForeignKey( + name: "fk_realm_tags_realms_realm_id", + column: x => x.realm_id, + principalTable: "realms", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_realm_tags_tags_tag_id", + column: x => x.tag_id, + principalTable: "tags", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "chat_members", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + chat_room_id = table.Column(type: "uuid", nullable: false), + account_id = table.Column(type: "uuid", nullable: false), + nick = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + role = table.Column(type: "integer", nullable: false), + notify = table.Column(type: "integer", nullable: false), + last_read_at = table.Column(type: "timestamp with time zone", nullable: true), + joined_at = table.Column(type: "timestamp with time zone", nullable: true), + leave_at = table.Column(type: "timestamp with time zone", nullable: true), + is_bot = table.Column(type: "boolean", nullable: false), + break_until = table.Column(type: "timestamp with time zone", nullable: true), + timeout_until = table.Column(type: "timestamp with time zone", nullable: true), + timeout_cause = table.Column(type: "jsonb", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_chat_members", x => x.id); + table.UniqueConstraint("ak_chat_members_chat_room_id_account_id", x => new { x.chat_room_id, x.account_id }); + table.ForeignKey( + name: "fk_chat_members_chat_rooms_chat_room_id", + column: x => x.chat_room_id, + principalTable: "chat_rooms", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "custom_apps", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + slug = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + status = table.Column(type: "integer", nullable: false), + picture = table.Column(type: "jsonb", nullable: true), + background = table.Column(type: "jsonb", nullable: true), + verification = table.Column(type: "jsonb", nullable: true), + oauth_config = table.Column(type: "jsonb", nullable: true), + links = table.Column(type: "jsonb", nullable: true), + publisher_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_custom_apps", x => x.id); + table.ForeignKey( + name: "fk_custom_apps_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_collections", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + publisher_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_collections", x => x.id); + table.ForeignKey( + name: "fk_post_collections_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "posts", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + title = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + language = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + edited_at = table.Column(type: "timestamp with time zone", nullable: true), + published_at = table.Column(type: "timestamp with time zone", nullable: true), + visibility = table.Column(type: "integer", nullable: false), + content = table.Column(type: "text", nullable: true), + type = table.Column(type: "integer", nullable: false), + meta = table.Column>(type: "jsonb", nullable: true), + sensitive_marks = table.Column>(type: "jsonb", nullable: true), + views_unique = table.Column(type: "integer", nullable: false), + views_total = table.Column(type: "integer", nullable: false), + upvotes = table.Column(type: "integer", nullable: false), + downvotes = table.Column(type: "integer", nullable: false), + replied_post_id = table.Column(type: "uuid", nullable: true), + forwarded_post_id = table.Column(type: "uuid", nullable: true), + attachments = table.Column>(type: "jsonb", nullable: false), + search_vector = table.Column(type: "tsvector", nullable: false) + .Annotation("Npgsql:TsVectorConfig", "simple") + .Annotation("Npgsql:TsVectorProperties", new[] { "title", "description", "content" }), + publisher_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_posts", x => x.id); + table.ForeignKey( + name: "fk_posts_posts_forwarded_post_id", + column: x => x.forwarded_post_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "fk_posts_posts_replied_post_id", + column: x => x.replied_post_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "fk_posts_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "publisher_features", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + flag = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + publisher_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_publisher_features", x => x.id); + table.ForeignKey( + name: "fk_publisher_features_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "publisher_members", + columns: table => new + { + publisher_id = table.Column(type: "uuid", nullable: false), + account_id = table.Column(type: "uuid", nullable: false), + role = table.Column(type: "integer", nullable: false), + joined_at = table.Column(type: "timestamp with time zone", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_publisher_members", x => new { x.publisher_id, x.account_id }); + table.ForeignKey( + name: "fk_publisher_members_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "publisher_subscriptions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + publisher_id = table.Column(type: "uuid", nullable: false), + account_id = table.Column(type: "uuid", nullable: false), + status = table.Column(type: "integer", nullable: false), + tier = table.Column(type: "integer", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_publisher_subscriptions", x => x.id); + table.ForeignKey( + name: "fk_publisher_subscriptions_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "sticker_packs", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), + prefix = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + publisher_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_sticker_packs", x => x.id); + table.ForeignKey( + name: "fk_sticker_packs_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "web_feeds", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + url = table.Column(type: "character varying(8192)", maxLength: 8192, nullable: false), + title = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), + description = table.Column(type: "character varying(8192)", maxLength: 8192, nullable: true), + preview = table.Column(type: "jsonb", nullable: true), + config = table.Column(type: "jsonb", nullable: false), + publisher_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_web_feeds", x => x.id); + table.ForeignKey( + name: "fk_web_feeds_publishers_publisher_id", + column: x => x.publisher_id, + principalTable: "publishers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "chat_messages", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + type = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + content = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + meta = table.Column>(type: "jsonb", nullable: true), + members_mentioned = table.Column>(type: "jsonb", nullable: true), + nonce = table.Column(type: "character varying(36)", maxLength: 36, nullable: false), + edited_at = table.Column(type: "timestamp with time zone", nullable: true), + attachments = table.Column>(type: "jsonb", nullable: false), + replied_message_id = table.Column(type: "uuid", nullable: true), + forwarded_message_id = table.Column(type: "uuid", nullable: true), + sender_id = table.Column(type: "uuid", nullable: false), + chat_room_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_chat_messages", x => x.id); + table.ForeignKey( + name: "fk_chat_messages_chat_members_sender_id", + column: x => x.sender_id, + principalTable: "chat_members", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_chat_messages_chat_messages_forwarded_message_id", + column: x => x.forwarded_message_id, + principalTable: "chat_messages", + principalColumn: "id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "fk_chat_messages_chat_messages_replied_message_id", + column: x => x.replied_message_id, + principalTable: "chat_messages", + principalColumn: "id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "fk_chat_messages_chat_rooms_chat_room_id", + column: x => x.chat_room_id, + principalTable: "chat_rooms", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "chat_realtime_call", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + ended_at = table.Column(type: "timestamp with time zone", nullable: true), + sender_id = table.Column(type: "uuid", nullable: false), + room_id = table.Column(type: "uuid", nullable: false), + provider_name = table.Column(type: "text", nullable: true), + session_id = table.Column(type: "text", nullable: true), + upstream = table.Column(type: "jsonb", nullable: true), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_chat_realtime_call", x => x.id); + table.ForeignKey( + name: "fk_chat_realtime_call_chat_members_sender_id", + column: x => x.sender_id, + principalTable: "chat_members", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_chat_realtime_call_chat_rooms_room_id", + column: x => x.room_id, + principalTable: "chat_rooms", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "custom_app_secrets", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + secret = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + is_oidc = table.Column(type: "boolean", nullable: false), + app_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_custom_app_secrets", x => x.id); + table.ForeignKey( + name: "fk_custom_app_secrets_custom_apps_app_id", + column: x => x.app_id, + principalTable: "custom_apps", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_category_links", + columns: table => new + { + categories_id = table.Column(type: "uuid", nullable: false), + posts_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_post_category_links", x => new { x.categories_id, x.posts_id }); + table.ForeignKey( + name: "fk_post_category_links_post_categories_categories_id", + column: x => x.categories_id, + principalTable: "post_categories", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_category_links_posts_posts_id", + column: x => x.posts_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_collection_links", + columns: table => new + { + collections_id = table.Column(type: "uuid", nullable: false), + posts_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_post_collection_links", x => new { x.collections_id, x.posts_id }); + table.ForeignKey( + name: "fk_post_collection_links_post_collections_collections_id", + column: x => x.collections_id, + principalTable: "post_collections", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_collection_links_posts_posts_id", + column: x => x.posts_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_reactions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + symbol = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + attitude = table.Column(type: "integer", nullable: false), + post_id = table.Column(type: "uuid", nullable: false), + account_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_post_reactions", x => x.id); + table.ForeignKey( + name: "fk_post_reactions_posts_post_id", + column: x => x.post_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "post_tag_links", + columns: table => new + { + posts_id = table.Column(type: "uuid", nullable: false), + tags_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_post_tag_links", x => new { x.posts_id, x.tags_id }); + table.ForeignKey( + name: "fk_post_tag_links_post_tags_tags_id", + column: x => x.tags_id, + principalTable: "post_tags", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_post_tag_links_posts_posts_id", + column: x => x.posts_id, + principalTable: "posts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "stickers", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + slug = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + image_id = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + image = table.Column(type: "jsonb", nullable: true), + pack_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_stickers", x => x.id); + table.ForeignKey( + name: "fk_stickers_sticker_packs_pack_id", + column: x => x.pack_id, + principalTable: "sticker_packs", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "web_articles", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + title = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: false), + url = table.Column(type: "character varying(8192)", maxLength: 8192, nullable: false), + author = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + meta = table.Column>(type: "jsonb", nullable: true), + preview = table.Column(type: "jsonb", nullable: true), + content = table.Column(type: "text", nullable: true), + published_at = table.Column(type: "timestamp with time zone", nullable: true), + feed_id = table.Column(type: "uuid", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_web_articles", x => x.id); + table.ForeignKey( + name: "fk_web_articles_web_feeds_feed_id", + column: x => x.feed_id, + principalTable: "web_feeds", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "chat_reactions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + message_id = table.Column(type: "uuid", nullable: false), + sender_id = table.Column(type: "uuid", nullable: false), + symbol = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + attitude = table.Column(type: "integer", nullable: false), + created_at = table.Column(type: "timestamp with time zone", nullable: false), + updated_at = table.Column(type: "timestamp with time zone", nullable: false), + deleted_at = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_chat_reactions", x => x.id); + table.ForeignKey( + name: "fk_chat_reactions_chat_members_sender_id", + column: x => x.sender_id, + principalTable: "chat_members", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_chat_reactions_chat_messages_message_id", + column: x => x.message_id, + principalTable: "chat_messages", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_chat_messages_chat_room_id", + table: "chat_messages", + column: "chat_room_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_messages_forwarded_message_id", + table: "chat_messages", + column: "forwarded_message_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_messages_replied_message_id", + table: "chat_messages", + column: "replied_message_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_messages_sender_id", + table: "chat_messages", + column: "sender_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_reactions_message_id", + table: "chat_reactions", + column: "message_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_reactions_sender_id", + table: "chat_reactions", + column: "sender_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_realtime_call_room_id", + table: "chat_realtime_call", + column: "room_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_realtime_call_sender_id", + table: "chat_realtime_call", + column: "sender_id"); + + migrationBuilder.CreateIndex( + name: "ix_chat_rooms_realm_id", + table: "chat_rooms", + column: "realm_id"); + + migrationBuilder.CreateIndex( + name: "ix_custom_app_secrets_app_id", + table: "custom_app_secrets", + column: "app_id"); + + migrationBuilder.CreateIndex( + name: "ix_custom_app_secrets_secret", + table: "custom_app_secrets", + column: "secret", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_custom_apps_publisher_id", + table: "custom_apps", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_category_links_posts_id", + table: "post_category_links", + column: "posts_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_collection_links_posts_id", + table: "post_collection_links", + column: "posts_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_collections_publisher_id", + table: "post_collections", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_reactions_post_id", + table: "post_reactions", + column: "post_id"); + + migrationBuilder.CreateIndex( + name: "ix_post_tag_links_tags_id", + table: "post_tag_links", + column: "tags_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_forwarded_post_id", + table: "posts", + column: "forwarded_post_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_publisher_id", + table: "posts", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_replied_post_id", + table: "posts", + column: "replied_post_id"); + + migrationBuilder.CreateIndex( + name: "ix_posts_search_vector", + table: "posts", + column: "search_vector") + .Annotation("Npgsql:IndexMethod", "GIN"); + + migrationBuilder.CreateIndex( + name: "ix_publisher_features_publisher_id", + table: "publisher_features", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_publisher_subscriptions_publisher_id", + table: "publisher_subscriptions", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_publishers_name", + table: "publishers", + column: "name", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_publishers_realm_id", + table: "publishers", + column: "realm_id"); + + migrationBuilder.CreateIndex( + name: "ix_realm_tags_tag_id", + table: "realm_tags", + column: "tag_id"); + + migrationBuilder.CreateIndex( + name: "ix_realms_slug", + table: "realms", + column: "slug", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_sticker_packs_prefix", + table: "sticker_packs", + column: "prefix", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_sticker_packs_publisher_id", + table: "sticker_packs", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_stickers_pack_id", + table: "stickers", + column: "pack_id"); + + migrationBuilder.CreateIndex( + name: "ix_stickers_slug", + table: "stickers", + column: "slug"); + + migrationBuilder.CreateIndex( + name: "ix_web_articles_feed_id", + table: "web_articles", + column: "feed_id"); + + migrationBuilder.CreateIndex( + name: "ix_web_articles_url", + table: "web_articles", + column: "url", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_web_feeds_publisher_id", + table: "web_feeds", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_web_feeds_url", + table: "web_feeds", + column: "url", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "chat_reactions"); + + migrationBuilder.DropTable( + name: "chat_realtime_call"); + + migrationBuilder.DropTable( + name: "custom_app_secrets"); + + migrationBuilder.DropTable( + name: "post_category_links"); + + migrationBuilder.DropTable( + name: "post_collection_links"); + + migrationBuilder.DropTable( + name: "post_reactions"); + + migrationBuilder.DropTable( + name: "post_tag_links"); + + migrationBuilder.DropTable( + name: "publisher_features"); + + migrationBuilder.DropTable( + name: "publisher_members"); + + migrationBuilder.DropTable( + name: "publisher_subscriptions"); + + migrationBuilder.DropTable( + name: "realm_members"); + + migrationBuilder.DropTable( + name: "realm_tags"); + + migrationBuilder.DropTable( + name: "stickers"); + + migrationBuilder.DropTable( + name: "web_articles"); + + migrationBuilder.DropTable( + name: "chat_messages"); + + migrationBuilder.DropTable( + name: "custom_apps"); + + migrationBuilder.DropTable( + name: "post_categories"); + + migrationBuilder.DropTable( + name: "post_collections"); + + migrationBuilder.DropTable( + name: "post_tags"); + + migrationBuilder.DropTable( + name: "posts"); + + migrationBuilder.DropTable( + name: "tags"); + + migrationBuilder.DropTable( + name: "sticker_packs"); + + migrationBuilder.DropTable( + name: "web_feeds"); + + migrationBuilder.DropTable( + name: "chat_members"); + + migrationBuilder.DropTable( + name: "publishers"); + + migrationBuilder.DropTable( + name: "chat_rooms"); + + migrationBuilder.DropTable( + name: "realms"); + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs new file mode 100644 index 0000000..3f29a76 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs @@ -0,0 +1,1879 @@ +// +using System; +using System.Collections.Generic; +using DysonNetwork.Shared.Data; +using DysonNetwork.Sphere; +using DysonNetwork.Sphere.Chat; +using DysonNetwork.Sphere.Developer; +using DysonNetwork.Sphere.WebReader; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using NpgsqlTypes; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + [DbContext(typeof(AppDatabase))] + partial class AppDatabaseModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatMember", 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("IsBot") + .HasColumnType("boolean") + .HasColumnName("is_bot"); + + 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("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + 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.ToTable("chat_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Background") + .HasColumnType("jsonb") + .HasColumnName("background"); + + b.Property("BackgroundId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("background_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("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("PictureId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("picture_id"); + + 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.HasIndex("RealmId") + .HasDatabaseName("ix_chat_rooms_realm_id"); + + b.ToTable("chat_rooms", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", 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.Property>("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.Sphere.Chat.MessageReaction", 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.Sphere.Chat.RealtimeCall", 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.Sphere.Developer.CustomApp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("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("Links") + .HasColumnType("jsonb") + .HasColumnName("links"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("OauthConfig") + .HasColumnType("jsonb") + .HasColumnName("oauth_config"); + + b.Property("Picture") + .HasColumnType("jsonb") + .HasColumnName("picture"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("slug"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Verification") + .HasColumnType("jsonb") + .HasColumnName("verification"); + + b.HasKey("Id") + .HasName("pk_custom_apps"); + + b.HasIndex("PublisherId") + .HasDatabaseName("ix_custom_apps_publisher_id"); + + b.ToTable("custom_apps", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomAppSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_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("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("IsOidc") + .HasColumnType("boolean") + .HasColumnName("is_oidc"); + + b.Property("Secret") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("secret"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_custom_app_secrets"); + + b.HasIndex("AppId") + .HasDatabaseName("ix_custom_app_secrets_app_id"); + + b.HasIndex("Secret") + .IsUnique() + .HasDatabaseName("ix_custom_app_secrets_secret"); + + b.ToTable("custom_app_secrets", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property>("Attachments") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("attachments"); + + 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("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("ForwardedPostId") + .HasColumnType("uuid") + .HasColumnName("forwarded_post_id"); + + b.Property("Language") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("language"); + + b.Property>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("PublishedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("published_at"); + + b.Property("PublisherId") + .HasColumnType("uuid") + .HasColumnName("publisher_id"); + + b.Property("RepliedPostId") + .HasColumnType("uuid") + .HasColumnName("replied_post_id"); + + b.Property("SearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("tsvector") + .HasColumnName("search_vector") + .HasAnnotation("Npgsql:TsVectorConfig", "simple") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "Title", "Description", "Content" }); + + b.Property>("SensitiveMarks") + .HasColumnType("jsonb") + .HasColumnName("sensitive_marks"); + + 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("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.HasIndex("SearchVector") + .HasDatabaseName("ix_posts_search_vector"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("SearchVector"), "GIN"); + + b.ToTable("posts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCategory", 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.Sphere.Post.PostCollection", 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.Sphere.Post.PostReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_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("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("PostId") + .HasDatabaseName("ix_post_reactions_post_id"); + + b.ToTable("post_reactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostTag", 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.Sphere.Publisher.Publisher", 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("BackgroundId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("background_id"); + + 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("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("PictureId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("picture_id"); + + 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.HasIndex("RealmId") + .HasDatabaseName("ix_publishers_realm_id"); + + b.ToTable("publishers", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherFeature", 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.Sphere.Publisher.PublisherMember", 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.Sphere.Publisher.PublisherSubscription", 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.Sphere.Realm.Realm", 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("BackgroundId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("background_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("IsCommunity") + .HasColumnType("boolean") + .HasColumnName("is_community"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("is_public"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("Picture") + .HasColumnType("jsonb") + .HasColumnName("picture"); + + b.Property("PictureId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("picture_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("slug"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Verification") + .HasColumnType("jsonb") + .HasColumnName("verification"); + + b.HasKey("Id") + .HasName("pk_realms"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_realms_slug"); + + b.ToTable("realms", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b => + { + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_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("LeaveAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("leave_at"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("RealmId", "AccountId") + .HasName("pk_realm_members"); + + b.ToTable("realm_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmTag", b => + { + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_id"); + + b.Property("TagId") + .HasColumnType("uuid") + .HasColumnName("tag_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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("RealmId", "TagId") + .HasName("pk_realm_tags"); + + b.HasIndex("TagId") + .HasDatabaseName("ix_realm_tags_tag_id"); + + b.ToTable("realm_tags", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Tag", 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") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("name"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_tags"); + + b.ToTable("tags", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", 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") + .HasColumnType("jsonb") + .HasColumnName("image"); + + b.Property("ImageId") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("image_id"); + + 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.Sphere.Sticker.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("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.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("PostPostCategory", 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("PostPostCollection", 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("PostPostTag", 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.Sphere.Chat.ChatMember", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "ChatRoom") + .WithMany("Members") + .HasForeignKey("ChatRoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_members_chat_rooms_chat_room_id"); + + b.Navigation("ChatRoom"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("ChatRooms") + .HasForeignKey("RealmId") + .HasConstraintName("fk_chat_rooms_realms_realm_id"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "ChatRoom") + .WithMany() + .HasForeignKey("ChatRoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_messages_chat_rooms_chat_room_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.Message", "ForwardedMessage") + .WithMany() + .HasForeignKey("ForwardedMessageId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_chat_messages_chat_messages_forwarded_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.Message", "RepliedMessage") + .WithMany() + .HasForeignKey("RepliedMessageId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_chat_messages_chat_messages_replied_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "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.Sphere.Chat.MessageReaction", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.Message", "Message") + .WithMany("Reactions") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_reactions_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "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.Sphere.Chat.RealtimeCall", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.ChatRoom", "Room") + .WithMany() + .HasForeignKey("RoomId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_realtime_call_chat_rooms_room_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "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.Sphere.Developer.CustomApp", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Developer") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_custom_apps_publishers_publisher_id"); + + b.Navigation("Developer"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomAppSecret", b => + { + b.HasOne("DysonNetwork.Sphere.Developer.CustomApp", "App") + .WithMany("Secrets") + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_custom_app_secrets_custom_apps_app_id"); + + b.Navigation("App"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Post", "ForwardedPost") + .WithMany() + .HasForeignKey("ForwardedPostId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_posts_posts_forwarded_post_id"); + + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Posts") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_posts_publishers_publisher_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", "RepliedPost") + .WithMany() + .HasForeignKey("RepliedPostId") + .OnDelete(DeleteBehavior.Restrict) + .HasConstraintName("fk_posts_posts_replied_post_id"); + + b.Navigation("ForwardedPost"); + + b.Navigation("Publisher"); + + b.Navigation("RepliedPost"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Collections") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collections_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostReaction", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Post", "Post") + .WithMany("Reactions") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_posts_post_id"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany() + .HasForeignKey("RealmId") + .HasConstraintName("fk_publishers_realms_realm_id"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherFeature", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Features") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_features_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherMember", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Members") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Subscriptions") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("Members") + .HasForeignKey("RealmId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_members_realms_realm_id"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmTag", b => + { + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("RealmTags") + .HasForeignKey("RealmId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_tags_realms_realm_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Tag", "Tag") + .WithMany("RealmTags") + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_tags_tags_tag_id"); + + b.Navigation("Realm"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b => + { + b.HasOne("DysonNetwork.Sphere.Sticker.StickerPack", "Pack") + .WithMany() + .HasForeignKey("PackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_sticker_packs_pack_id"); + + b.Navigation("Pack"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.StickerPack", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_sticker_packs_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + 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.Sphere.Publisher.Publisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_web_feeds_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("PostPostCategory", b => + { + b.HasOne("DysonNetwork.Sphere.Post.PostCategory", null) + .WithMany() + .HasForeignKey("CategoriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_category_links_post_categories_categories_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_category_links_posts_posts_id"); + }); + + modelBuilder.Entity("PostPostCollection", b => + { + b.HasOne("DysonNetwork.Sphere.Post.PostCollection", null) + .WithMany() + .HasForeignKey("CollectionsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collection_links_post_collections_collections_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_collection_links_posts_posts_id"); + }); + + modelBuilder.Entity("PostPostTag", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany() + .HasForeignKey("PostsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_tag_links_posts_posts_id"); + + b.HasOne("DysonNetwork.Sphere.Post.PostTag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_tag_links_post_tags_tags_id"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", b => + { + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomApp", b => + { + b.Navigation("Secrets"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => + { + b.Navigation("Collections"); + + b.Navigation("Features"); + + b.Navigation("Members"); + + b.Navigation("Posts"); + + b.Navigation("Subscriptions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b => + { + b.Navigation("ChatRooms"); + + b.Navigation("Members"); + + b.Navigation("RealmTags"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Tag", b => + { + b.Navigation("RealmTags"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.WebReader.WebFeed", b => + { + b.Navigation("Articles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Sphere/Program.cs b/DysonNetwork.Sphere/Program.cs index 8471b02..56d4590 100644 --- a/DysonNetwork.Sphere/Program.cs +++ b/DysonNetwork.Sphere/Program.cs @@ -3,7 +3,6 @@ using DysonNetwork.Shared.Registry; using DysonNetwork.Sphere; using DysonNetwork.Sphere.Startup; using Microsoft.EntityFrameworkCore; -using tusdotnet.Stores; var builder = WebApplication.CreateBuilder(args); diff --git a/DysonNetwork.Sphere/Publisher/PublisherController.cs b/DysonNetwork.Sphere/Publisher/PublisherController.cs index e541d68..f18fba0 100644 --- a/DysonNetwork.Sphere/Publisher/PublisherController.cs +++ b/DysonNetwork.Sphere/Publisher/PublisherController.cs @@ -502,8 +502,6 @@ public class PublisherController( var publisher = await db.Publishers .Where(p => p.Name == name) - .Include(publisher => publisher.Picture) - .Include(publisher => publisher.Background) .FirstOrDefaultAsync(); if (publisher is null) return NotFound(); diff --git a/DysonNetwork.Sphere/Realm/RealmController.cs.bak b/DysonNetwork.Sphere/Realm/RealmController.cs.bak deleted file mode 100644 index 449df8e..0000000 --- a/DysonNetwork.Sphere/Realm/RealmController.cs.bak +++ /dev/null @@ -1,696 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using DysonNetwork.Shared.Data; -using DysonNetwork.Shared.Proto; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using NodaTime; -using Google.Protobuf.WellKnownTypes; - -namespace DysonNetwork.Sphere.Realm; - -[ApiController] -[Route("/api/realms")] -public class RealmController( - AppDatabase db, - RealmService rs, - FileReferenceService.FileReferenceServiceClient fileRefs, - ActionLogService.ActionLogServiceClient als, - AccountService.AccountServiceClient accounts -) : Controller -{ - [HttpGet("{slug}")] - public async Task> GetRealm(string slug) - { - var realm = await db.Realms - .Where(e => e.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - return Ok(realm); - } - - [HttpGet] - [Authorize] - public async Task>> ListJoinedRealms() - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var members = await db.RealmMembers - .Where(m => m.AccountId == accountId) - .Where(m => m.JoinedAt != null) - .Where(m => m.LeaveAt == null) - .Include(e => e.Realm) - .Select(m => m.Realm) - .ToListAsync(); - - return members.ToList(); - } - - [HttpGet("invites")] - [Authorize] - public async Task>> ListInvites() - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var members = await db.RealmMembers - .Where(m => m.AccountId == accountId) - .Where(m => m.JoinedAt == null) - .Include(e => e.Realm) - .ToListAsync(); - - return members.ToList(); - } - - public class RealmMemberRequest - { - [Required] public Guid RelatedUserId { get; set; } - [Required] public int Role { get; set; } - } - - [HttpPost("invites/{slug}")] - [Authorize] - public async Task> InviteMember(string slug, - [FromBody] RealmMemberRequest request) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var relatedUser = - await accounts.GetAccountAsync(new GetAccountRequest { Id = request.RelatedUserId.ToString() }); - if (relatedUser == null) return BadRequest("Related user was not found"); - - var hasBlocked = await accounts.HasRelationshipAsync(new GetRelationshipRequest() - { - AccountId = currentUser.Id, - RelatedId = request.RelatedUserId.ToString(), - Status = -100 - }); - if (hasBlocked?.Value ?? false) - return StatusCode(403, "You cannot invite a user that blocked you."); - - var realm = await db.Realms - .Where(p => p.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - if (!await rs.IsMemberWithRole(realm.Id, accountId, request.Role)) - return StatusCode(403, "You cannot invite member has higher permission than yours."); - - var hasExistingMember = await db.RealmMembers - .Where(m => m.AccountId == Guid.Parse(relatedUser.Id)) - .Where(m => m.RealmId == realm.Id) - .Where(m => m.LeaveAt == null) - .AnyAsync(); - if (hasExistingMember) - return BadRequest("This user has been joined the realm or leave cannot be invited again."); - - var member = new RealmMember - { - AccountId = Guid.Parse(relatedUser.Id), - RealmId = realm.Id, - Role = request.Role, - }; - - db.RealmMembers.Add(member); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.members.invite", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "account_id", Value.ForString(member.AccountId.ToString()) }, - { "role", Value.ForNumber(request.Role) } - }, - AccountId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - member.Account = relatedUser; - member.Realm = realm; - await rs.SendInviteNotify(member); - - return Ok(member); - } - - [HttpPost("invites/{slug}/accept")] - [Authorize] - public async Task> AcceptMemberInvite(string slug) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var member = await db.RealmMembers - .Where(m => m.AccountId == accountId) - .Where(m => m.Realm.Slug == slug) - .Where(m => m.JoinedAt == null) - .FirstOrDefaultAsync(); - if (member is null) return NotFound(); - - member.JoinedAt = NodaTime.Instant.FromDateTimeUtc(DateTime.UtcNow); - db.Update(member); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.members.join", - Meta = - { - { "realm_id", Value.ForString(member.RealmId.ToString()) }, - { "account_id", Value.ForString(member.AccountId.ToString()) } - }, - AccountId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - return Ok(member); - } - - [HttpPost("invites/{slug}/decline")] - [Authorize] - public async Task DeclineMemberInvite(string slug) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var member = await db.RealmMembers - .Where(m => m.AccountId == accountId) - .Where(m => m.Realm.Slug == slug) - .Where(m => m.JoinedAt == null) - .FirstOrDefaultAsync(); - if (member is null) return NotFound(); - - member.LeaveAt = SystemClock.Instance.GetCurrentInstant(); - await db.SaveChangesAsync(); - - als.CreateActionLogFromRequest( - ActionLogType.RealmLeave, - new Dictionary { { "realm_id", member.RealmId }, { "account_id", member.AccountId } }, - Request - ); - - return NoContent(); - } - - - [HttpGet("{slug}/members")] - public async Task>> ListMembers( - string slug, - [FromQuery] int offset = 0, - [FromQuery] int take = 20, - [FromQuery] bool withStatus = false, - [FromQuery] string? status = null - ) - { - var realm = await db.Realms - .Where(r => r.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - if (!realm.IsPublic) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - if (!await rs.IsMemberWithRole(realm.Id, Guid.Parse(currentUser.Id), RealmMemberRole.Normal)) - return StatusCode(403, "You must be a member to view this realm's members."); - } - - IQueryable query = db.RealmMembers - .Where(m => m.RealmId == realm.Id) - .Where(m => m.LeaveAt == null) - .Include(m => m.Account) - .Include(m => m.Account.Profile); - - if (withStatus) - { - var members = await query - .OrderBy(m => m.CreatedAt) - .ToListAsync(); - - var memberStatuses = await aes.GetStatuses(members.Select(m => m.AccountId).ToList()); - - if (!string.IsNullOrEmpty(status)) - { - members = members.Where(m => - memberStatuses.TryGetValue(m.AccountId, out var s) && s.Label != null && - s.Label.Equals(status, StringComparison.OrdinalIgnoreCase)).ToList(); - } - - members = members.OrderByDescending(m => memberStatuses.TryGetValue(m.AccountId, out var s) && s.IsOnline) - .ToList(); - - var total = members.Count; - Response.Headers["X-Total"] = total.ToString(); - - var result = members.Skip(offset).Take(take).ToList(); - - return Ok(result); - } - else - { - var total = await query.CountAsync(); - Response.Headers["X-Total"] = total.ToString(); - - var members = await query - .OrderBy(m => m.CreatedAt) - .Skip(offset) - .Take(take) - .ToListAsync(); - - return Ok(members); - } - } - - - [HttpGet("{slug}/members/me")] - [Authorize] - public async Task> GetCurrentIdentity(string slug) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var member = await db.RealmMembers - .Where(m => m.AccountId == accountId) - .Where(m => m.Realm.Slug == slug) - .FirstOrDefaultAsync(); - - if (member is null) return NotFound(); - return Ok(member); - } - - [HttpDelete("{slug}/members/me")] - [Authorize] - public async Task LeaveRealm(string slug) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - var accountId = Guid.Parse(currentUser.Id); - - var member = await db.RealmMembers - .Where(m => m.AccountId == accountId) - .Where(m => m.Realm.Slug == slug) - .Where(m => m.JoinedAt != null) - .FirstOrDefaultAsync(); - if (member is null) return NotFound(); - - if (member.Role == RealmMemberRole.Owner) - return StatusCode(403, "Owner cannot leave their own realm."); - - member.LeaveAt = SystemClock.Instance.GetCurrentInstant(); - await db.SaveChangesAsync(); - - als.CreateActionLogFromRequest( - ActionLogType.RealmLeave, - new Dictionary { { "realm_id", member.RealmId }, { "account_id", member.AccountId } }, - Request - ); - - return NoContent(); - } - - public class RealmRequest - { - [MaxLength(1024)] public string? Slug { get; set; } - [MaxLength(1024)] public string? Name { get; set; } - [MaxLength(4096)] public string? Description { get; set; } - public string? PictureId { get; set; } - public string? BackgroundId { get; set; } - public bool? IsCommunity { get; set; } - public bool? IsPublic { get; set; } - } - - [HttpPost] - [Authorize] - public async Task> CreateRealm(RealmRequest request) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - if (string.IsNullOrWhiteSpace(request.Name)) return BadRequest("You cannot create a realm without a name."); - if (string.IsNullOrWhiteSpace(request.Slug)) return BadRequest("You cannot create a realm without a slug."); - - var slugExists = await db.Realms.AnyAsync(r => r.Slug == request.Slug); - if (slugExists) return BadRequest("Realm with this slug already exists."); - - var realm = new Realm - { - Name = request.Name!, - Slug = request.Slug!, - Description = request.Description!, - AccountId = currentUser.Id, - IsCommunity = request.IsCommunity ?? false, - IsPublic = request.IsPublic ?? false, - Members = new List - { - new() - { - Role = RealmMemberRole.Owner, - AccountId = Guid.Parse(currentUser.Id), - JoinedAt = NodaTime.Instant.FromDateTimeUtc(DateTime.UtcNow) - } - } - }; - - if (request.PictureId is not null) - { - var pictureResult = await files.GetFileAsync(new GetFileRequest { Id = request.PictureId }); - if (pictureResult is null) return BadRequest("Invalid picture id, unable to find the file on cloud."); - realm.Picture = CloudFileReferenceObject.FromProtoValue(pictureResult); - } - - if (request.BackgroundId is not null) - { - var backgroundResult = await files.GetFileAsync(new GetFileRequest { Id = request.BackgroundId }); - if (backgroundResult is null) return BadRequest("Invalid background id, unable to find the file on cloud."); - realm.Background = CloudFileReferenceObject.FromProtoValue(backgroundResult); - } - - db.Realms.Add(realm); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.create", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "name", Value.ForString(realm.Name) }, - { "slug", Value.ForString(realm.Slug) }, - { "is_community", Value.ForBool(realm.IsCommunity) }, - { "is_public", Value.ForBool(realm.IsPublic) } - }, - UserId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - var realmResourceId = $"realm:{realm.Id}"; - - if (realm.Picture is not null) - { - await fileRefs.CreateReferenceAsync(new CreateReferenceRequest - { - FileId = realm.Picture.Id, - Usage = "realm.picture", - ResourceId = realmResourceId - }); - } - - if (realm.Background is not null) - { - await fileRefs.CreateReferenceAsync(new CreateReferenceRequest - { - FileId = realm.Background.Id, - Usage = "realm.background", - ResourceId = realmResourceId - }); - } - - return Ok(realm); - } - - [HttpPatch("{slug}")] - [Authorize] - public async Task> Update(string slug, [FromBody] RealmRequest request) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - - var realm = await db.Realms - .Where(r => r.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - var accountId = Guid.Parse(currentUser.Id); - var member = await db.RealmMembers - .Where(m => m.AccountId == accountId && m.RealmId == realm.Id && m.JoinedAt != null) - .FirstOrDefaultAsync(); - if (member is null || member.Role < RealmMemberRole.Moderator) - return StatusCode(403, "You do not have permission to update this realm."); - - if (request.Slug is not null && request.Slug != realm.Slug) - { - var slugExists = await db.Realms.AnyAsync(r => r.Slug == request.Slug); - if (slugExists) return BadRequest("Realm with this slug already exists."); - realm.Slug = request.Slug; - } - - if (request.Name is not null) - realm.Name = request.Name; - if (request.Description is not null) - realm.Description = request.Description; - if (request.IsCommunity is not null) - realm.IsCommunity = request.IsCommunity.Value; - if (request.IsPublic is not null) - realm.IsPublic = request.IsPublic.Value; - - if (request.PictureId is not null) - { - var pictureResult = await files.GetFileAsync(new GetFileRequest { Id = request.PictureId }); - if (pictureResult is null) return BadRequest("Invalid picture id, unable to find the file on cloud."); - - // Remove old references for the realm picture - if (realm.Picture is not null) - { - await fileRefs.DeleteResourceReferencesAsync(new DeleteResourceReferencesRequest - { - ResourceId = realm.ResourceIdentifier - }); - } - - realm.Picture = CloudFileReferenceObject.FromProtoValue(pictureResult); - - // Create a new reference - await fileRefs.CreateReferenceAsync(new CreateReferenceRequest - { - FileId = realm.Picture.Id, - Usage = "realm.picture", - ResourceId = realm.ResourceIdentifier - }); - } - - if (request.BackgroundId is not null) - { - var backgroundResult = await files.GetFileAsync(new GetFileRequest { Id = request.BackgroundId }); - if (backgroundResult is null) return BadRequest("Invalid background id, unable to find the file on cloud."); - - // Remove old references for the realm background - if (realm.Background is not null) - { - await fileRefs.DeleteResourceReferencesAsync(new DeleteResourceReferencesRequest - { - ResourceId = realm.ResourceIdentifier - }); - } - - realm.Background = CloudFileReferenceObject.FromProtoValue(backgroundResult); - - // Create a new reference - await fileRefs.CreateReferenceAsync(new CreateReferenceRequest - { - FileId = realm.Background.Id, - Usage = "realm.background", - ResourceId = realm.ResourceIdentifier - }); - } - - db.Realms.Update(realm); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.update", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "name_updated", Value.ForBool(request.Name != null) }, - { "slug_updated", Value.ForBool(request.Slug != null) }, - { "description_updated", Value.ForBool(request.Description != null) }, - { "picture_updated", Value.ForBool(request.PictureId != null) }, - { "background_updated", Value.ForBool(request.BackgroundId != null) }, - { "is_community_updated", Value.ForBool(request.IsCommunity != null) }, - { "is_public_updated", Value.ForBool(request.IsPublic != null) } - }, - UserId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - return Ok(realm); - } - - [HttpPost("{slug}/members/me")] - [Authorize] - public async Task> JoinRealm(string slug) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - - var realm = await db.Realms - .Where(r => r.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - if (!realm.IsCommunity) - return StatusCode(403, "Only community realms can be joined without invitation."); - - var existingMember = await db.RealmMembers - .Where(m => m.AccountId == Guid.Parse(currentUser.Id) && m.RealmId == realm.Id) - .FirstOrDefaultAsync(); - if (existingMember is not null) - return BadRequest("You are already a member of this realm."); - - var member = new RealmMember - { - AccountId = currentUser.Id, - RealmId = realm.Id, - Role = RealmMemberRole.Normal, - JoinedAt = NodaTime.Instant.FromDateTimeUtc(DateTime.UtcNow) - }; - - db.RealmMembers.Add(member); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.members.join", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "account_id", Value.ForString(currentUser.Id) }, - { "is_community", Value.ForBool(realm.IsCommunity) } - }, - UserId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - return Ok(member); - } - - [HttpDelete("{slug}/members/{memberId:guid}")] - [Authorize] - public async Task RemoveMember(string slug, Guid memberId) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - - var realm = await db.Realms - .Where(r => r.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - var member = await db.RealmMembers - .Where(m => m.AccountId == memberId && m.RealmId == realm.Id) - .FirstOrDefaultAsync(); - if (member is null) return NotFound(); - - if (!await rs.IsMemberWithRole(realm.Id, Guid.Parse(currentUser.Id), RealmMemberRole.Moderator, member.Role)) - return StatusCode(403, "You do not have permission to remove members from this realm."); - - member.LeaveAt = SystemClock.Instance.GetCurrentInstant(); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.members.kick", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "account_id", Value.ForString(memberId.ToString()) }, - { "kicker_id", Value.ForString(currentUser.Id) } - }, - UserId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - return NoContent(); - } - - [HttpPatch("{slug}/members/{memberId:guid}/role")] - [Authorize] - public async Task> UpdateMemberRole(string slug, Guid memberId, [FromBody] int newRole) - { - if (newRole >= RealmMemberRole.Owner) return BadRequest("Unable to set realm member to owner or greater role."); - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - - var realm = await db.Realms - .Where(r => r.Slug == slug) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - var member = await db.RealmMembers - .Where(m => m.AccountId == memberId && m.RealmId == realm.Id) - .Include(m => m.Account) - .FirstOrDefaultAsync(); - if (member is null) return NotFound(); - - if (!await rs.IsMemberWithRole(realm.Id, Guid.Parse(currentUser.Id), RealmMemberRole.Moderator, member.Role, - newRole)) - return StatusCode(403, "You do not have permission to update member roles in this realm."); - - member.Role = newRole; - db.RealmMembers.Update(member); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.members.role_update", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "account_id", Value.ForString(memberId.ToString()) }, - { "new_role", Value.ForNumber(newRole) }, - { "updater_id", Value.ForString(currentUser.Id) } - }, - UserId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - return Ok(member); - } - - [HttpDelete("{slug}")] - [Authorize] - public async Task Delete(string slug) - { - if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); - - var realm = await db.Realms - .Where(r => r.Slug == slug) - .Include(r => r.Picture) - .Include(r => r.Background) - .FirstOrDefaultAsync(); - if (realm is null) return NotFound(); - - if (!await rs.IsMemberWithRole(realm.Id, Guid.Parse(currentUser.Id), RealmMemberRole.Owner)) - return StatusCode(403, "Only the owner can delete this realm."); - - db.Realms.Remove(realm); - await db.SaveChangesAsync(); - - _ = als.CreateActionLogAsync(new CreateActionLogRequest - { - Action = "realms.delete", - Meta = - { - { "realm_id", Value.ForString(realm.Id.ToString()) }, - { "realm_name", Value.ForString(realm.Name) }, - { "realm_slug", Value.ForString(realm.Slug) } - }, - UserId = currentUser.Id, - UserAgent = Request.Headers.UserAgent.ToString(), - IpAddress = Request.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "" - }); - - // Delete all file references for this realm - var realmResourceId = $"realm:{realm.Id}"; - await fileRefs.DeleteResourceReferencesAsync(new DeleteResourceReferencesRequest - { - ResourceId = realmResourceId - }); - - return NoContent(); - } -} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Startup/ApplicationConfiguration.cs b/DysonNetwork.Sphere/Startup/ApplicationConfiguration.cs index 32a5e2b..b7ca2c8 100644 --- a/DysonNetwork.Sphere/Startup/ApplicationConfiguration.cs +++ b/DysonNetwork.Sphere/Startup/ApplicationConfiguration.cs @@ -2,7 +2,6 @@ using System.Net; using DysonNetwork.Shared.Auth; using Microsoft.AspNetCore.HttpOverrides; using Prometheus; -using tusdotnet; namespace DysonNetwork.Sphere.Startup; diff --git a/DysonNetwork.Sphere/Startup/ServiceCollectionExtensions.cs b/DysonNetwork.Sphere/Startup/ServiceCollectionExtensions.cs index d4dfa39..4d1a858 100644 --- a/DysonNetwork.Sphere/Startup/ServiceCollectionExtensions.cs +++ b/DysonNetwork.Sphere/Startup/ServiceCollectionExtensions.cs @@ -17,11 +17,9 @@ using System.Threading.RateLimiting; using DysonNetwork.Shared.Auth; using DysonNetwork.Shared.Cache; using DysonNetwork.Shared.GeoIp; -using DysonNetwork.Shared.Proto; using DysonNetwork.Sphere.WebReader; using DysonNetwork.Sphere.Developer; using DysonNetwork.Sphere.Discovery; -using tusdotnet.Stores; namespace DysonNetwork.Sphere.Startup; diff --git a/DysonNetwork.Sphere/appsettings.json b/DysonNetwork.Sphere/appsettings.json index f7023f6..23862a6 100644 --- a/DysonNetwork.Sphere/appsettings.json +++ b/DysonNetwork.Sphere/appsettings.json @@ -16,22 +16,10 @@ "GeoIp": { "DatabasePath": "./Keys/GeoLite2-City.mmdb" }, - "Oidc": { - "Google": { - "ClientId": "961776991058-963m1qin2vtp8fv693b5fdrab5hmpl89.apps.googleusercontent.com", - "ClientSecret": "" - }, - "Apple": { - "ClientId": "dev.solsynth.solian", - "TeamId": "W7HPZ53V6B", - "KeyId": "B668YP4KBG", - "PrivateKeyPath": "./Keys/Solarpass.p8" - }, - "Microsoft": { - "ClientId": "YOUR_MICROSOFT_CLIENT_ID", - "ClientSecret": "YOUR_MICROSOFT_CLIENT_SECRET", - "DiscoveryEndpoint": "YOUR_MICROSOFT_DISCOVERY_ENDPOINT" - } + "RealtimeChat": { + "Endpoint": "https://solar-network-im44o8gq.livekit.cloud", + "ApiKey": "APIs6TiL8wj3A4j", + "ApiSecret": "SffxRneIwTnlHPtEf3zicmmv3LUEl7xXael4PvWZrEhE" }, "KnownProxies": [ "127.0.0.1",