diff --git a/DysonNetwork.Sphere/AppDatabase.cs b/DysonNetwork.Sphere/AppDatabase.cs index bb28606..9e2cf97 100644 --- a/DysonNetwork.Sphere/AppDatabase.cs +++ b/DysonNetwork.Sphere/AppDatabase.cs @@ -1,5 +1,6 @@ using System.Linq.Expressions; using DysonNetwork.Sphere.Permission; +using DysonNetwork.Sphere.Publisher; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using NodaTime; @@ -43,9 +44,11 @@ public class AppDatabase( public DbSet Activities { get; set; } - public DbSet Publishers { get; set; } - public DbSet PublisherMembers { get; set; } - public DbSet PublisherSubscriptions { get; set; } + public DbSet Publishers { get; set; } + public DbSet PublisherMembers { get; set; } + public DbSet PublisherSubscriptions { get; set; } + public DbSet PublisherFeatures { get; set; } + public DbSet Posts { get; set; } public DbSet PostReactions { get; set; } public DbSet PostTags { get; set; } @@ -64,7 +67,14 @@ public class AppDatabase( public DbSet Stickers { get; set; } public DbSet StickerPacks { get; set; } + + public DbSet Wallets { get; set; } + public DbSet WalletPockets { get; set; } + public DbSet PaymentOrders { get; set; } + public DbSet PaymentTransactions { get; set; } + public DbSet CustomApps { get; set; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var dataSourceBuilder = new NpgsqlDataSourceBuilder(configuration.GetConnectionString("App")); @@ -138,24 +148,24 @@ public class AppDatabase( .WithMany(a => a.IncomingRelationships) .HasForeignKey(r => r.RelatedId); - modelBuilder.Entity() + modelBuilder.Entity() .HasKey(pm => new { pm.PublisherId, pm.AccountId }); - modelBuilder.Entity() + modelBuilder.Entity() .HasOne(pm => pm.Publisher) .WithMany(p => p.Members) .HasForeignKey(pm => pm.PublisherId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() + modelBuilder.Entity() .HasOne(pm => pm.Account) .WithMany() .HasForeignKey(pm => pm.AccountId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() + modelBuilder.Entity() .HasOne(ps => ps.Publisher) .WithMany(p => p.Subscriptions) .HasForeignKey(ps => ps.PublisherId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() + modelBuilder.Entity() .HasOne(ps => ps.Account) .WithMany() .HasForeignKey(ps => ps.AccountId) diff --git a/DysonNetwork.Sphere/Chat/ChatRoomController.cs b/DysonNetwork.Sphere/Chat/ChatRoomController.cs index eaf918f..883cf29 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomController.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomController.cs @@ -10,7 +10,7 @@ namespace DysonNetwork.Sphere.Chat; [ApiController] [Route("/chat")] -public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService crs) : ControllerBase +public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService crs, RealmService rs) : ControllerBase { [HttpGet("{id:guid}")] public async Task> GetChatRoom(Guid id) @@ -21,7 +21,7 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService .FirstOrDefaultAsync(); if (chatRoom is null) return NotFound(); if (chatRoom.Type != ChatRoomType.DirectMessage) return Ok(chatRoom); - + // Preload members for direct messages var currentUser = HttpContext.Items["CurrentUser"] as Account.Account; var directMembers = await db.ChatMembers @@ -168,13 +168,9 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService if (request.RealmId is not null) { - var member = await db.RealmMembers - .Where(m => m.AccountId == currentUser.Id) - .Where(m => m.RealmId == request.RealmId) - .FirstOrDefaultAsync(); - if (member is null || member.Role < RealmMemberRole.Moderator) + if (!await rs.IsMemberWithRole(request.RealmId.Value, currentUser.Id, RealmMemberRole.Moderator)) return StatusCode(403, "You need at least be a moderator to create chat linked to the realm."); - chatRoom.RealmId = member.RealmId; + chatRoom.RealmId = request.RealmId; } if (request.PictureId is not null) @@ -216,22 +212,11 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService if (chatRoom.RealmId is not null) { - var realmMember = await db.RealmMembers - .Where(m => m.AccountId == currentUser.Id) - .Where(m => m.RealmId == chatRoom.RealmId) - .FirstOrDefaultAsync(); - if (realmMember is null || realmMember.Role < RealmMemberRole.Moderator) + if (!await rs.IsMemberWithRole(chatRoom.RealmId.Value, currentUser.Id, RealmMemberRole.Moderator)) return StatusCode(403, "You need at least be a realm moderator to update the chat."); } - else - { - var chatMember = await db.ChatMembers - .Where(m => m.AccountId == currentUser.Id) - .Where(m => m.ChatRoomId == chatRoom.Id) - .FirstOrDefaultAsync(); - if (chatMember is null || chatMember.Role < ChatMemberRole.Moderator) - return StatusCode(403, "You need at least be a moderator to update the chat."); - } + else if (!await crs.IsMemberWithRole(chatRoom.Id, currentUser.Id, ChatMemberRole.Moderator)) + return StatusCode(403, "You need at least be a moderator to update the chat."); if (request.RealmId is not null) { @@ -287,22 +272,11 @@ public class ChatRoomController(AppDatabase db, FileService fs, ChatRoomService if (chatRoom.RealmId is not null) { - var realmMember = await db.RealmMembers - .Where(m => m.AccountId == currentUser.Id) - .Where(m => m.RealmId == chatRoom.RealmId) - .FirstOrDefaultAsync(); - if (realmMember is null || realmMember.Role < RealmMemberRole.Moderator) + if (!await rs.IsMemberWithRole(chatRoom.RealmId.Value, currentUser.Id, RealmMemberRole.Moderator)) return StatusCode(403, "You need at least be a realm moderator to delete the chat."); } - else - { - var chatMember = await db.ChatMembers - .Where(m => m.AccountId == currentUser.Id) - .Where(m => m.ChatRoomId == chatRoom.Id) - .FirstOrDefaultAsync(); - if (chatMember is null || chatMember.Role < ChatMemberRole.Owner) - return StatusCode(403, "You need at least be the owner to delete the chat."); - } + else if (!await crs.IsMemberWithRole(chatRoom.Id, currentUser.Id, ChatMemberRole.Owner)) + return StatusCode(403, "You need at least be the owner to delete the chat."); db.ChatRooms.Remove(chatRoom); await db.SaveChangesAsync(); diff --git a/DysonNetwork.Sphere/Chat/ChatRoomService.cs b/DysonNetwork.Sphere/Chat/ChatRoomService.cs index 28f7496..68acb5e 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomService.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomService.cs @@ -1,12 +1,20 @@ using DysonNetwork.Sphere.Account; +using Microsoft.EntityFrameworkCore; namespace DysonNetwork.Sphere.Chat; -public class ChatRoomService(NotificationService nty) +public class ChatRoomService(AppDatabase db, NotificationService nty) { public async Task SendInviteNotify(ChatMember member) { await nty.SendNotification(member.Account, "invites.chats", "New Chat Invitation", null, $"You just got invited to join {member.ChatRoom.Name}"); } + + public async Task IsMemberWithRole(Guid roomId, Guid accountId, ChatMemberRole requiredRole) + { + var member = await db.ChatMembers + .FirstOrDefaultAsync(m => m.ChatRoomId == roomId && m.AccountId == accountId); + return member?.Role >= requiredRole; + } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Developer/CustomApp.cs b/DysonNetwork.Sphere/Developer/CustomApp.cs new file mode 100644 index 0000000..8b7b561 --- /dev/null +++ b/DysonNetwork.Sphere/Developer/CustomApp.cs @@ -0,0 +1,25 @@ +using System.ComponentModel.DataAnnotations; +using NodaTime; + +namespace DysonNetwork.Sphere.Developer; + +public enum CustomAppStatus +{ + Developing, + Staging, + Production, + Suspended +} + +public class CustomApp : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + [MaxLength(1024)] public string Slug { get; set; } = null!; + [MaxLength(1024)] public string Name { get; set; } = null!; + public CustomAppStatus Status { get; set; } = CustomAppStatus.Developing; + public Instant? VerifiedAt { get; set; } + [MaxLength(4096)] public string? VerifiedAs { get; set; } + + public Guid PublisherId { get; set; } + public Publisher.Publisher Developer { get; set; } = null!; +} diff --git a/DysonNetwork.Sphere/Developer/CustomAppController.cs b/DysonNetwork.Sphere/Developer/CustomAppController.cs new file mode 100644 index 0000000..834a3f4 --- /dev/null +++ b/DysonNetwork.Sphere/Developer/CustomAppController.cs @@ -0,0 +1,11 @@ +using DysonNetwork.Sphere.Publisher; +using Microsoft.AspNetCore.Mvc; + +namespace DysonNetwork.Sphere.Developer; + +[ApiController] +[Route("/developers/apps")] +public class CustomAppController(PublisherService ps) : ControllerBase +{ + +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Migrations/20250514142322_WalletAndPayment.Designer.cs b/DysonNetwork.Sphere/Migrations/20250514142322_WalletAndPayment.Designer.cs new file mode 100644 index 0000000..e210a5d --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250514142322_WalletAndPayment.Designer.cs @@ -0,0 +1,3086 @@ +// +using System; +using System.Collections.Generic; +using System.Text.Json; +using DysonNetwork.Sphere; +using DysonNetwork.Sphere.Account; +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("20250514142322_WalletAndPayment")] + partial class WalletAndPayment + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ActivatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("activated_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("IsSuperuser") + .HasColumnType("boolean") + .HasColumnName("is_superuser"); + + b.Property("Language") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("language"); + + 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_accounts"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_accounts_name"); + + b.ToTable("accounts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", 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("Secret") + .HasMaxLength(8196) + .HasColumnType("character varying(8196)") + .HasColumnName("secret"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_auth_factors"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_auth_factors_account_id"); + + b.ToTable("account_auth_factors", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .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("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + b.HasKey("Id") + .HasName("pk_account_contacts"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_contacts_account_id"); + + b.ToTable("account_contacts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Badge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Caption") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("caption"); + + 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("Label") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("label"); + + b.Property>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + 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_badges"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_badges_account_id"); + + b.ToTable("badges", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.CheckInResult", 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("Level") + .HasColumnType("integer") + .HasColumnName("level"); + + b.Property>("Tips") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("tips"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_check_in_results"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_check_in_results_account_id"); + + b.ToTable("account_check_in_results", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Spell") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("spell"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_magic_spells"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_magic_spells_account_id"); + + b.HasIndex("Spell") + .IsUnique() + .HasDatabaseName("ix_magic_spells_spell"); + + b.ToTable("magic_spells", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_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>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("Subtitle") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("subtitle"); + + b.Property("Title") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("title"); + + b.Property("Topic") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("topic"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("ViewedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("viewed_at"); + + b.HasKey("Id") + .HasName("pk_notifications"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_notifications_account_id"); + + b.ToTable("notifications", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.NotificationPushSubscription", 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("DeviceId") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("device_id"); + + b.Property("DeviceToken") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("device_token"); + + b.Property("LastUsedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_used_at"); + + b.Property("Provider") + .HasColumnType("integer") + .HasColumnName("provider"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_notification_push_subscriptions"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_notification_push_subscriptions_account_id"); + + b.HasIndex("DeviceId") + .IsUnique() + .HasDatabaseName("ix_notification_push_subscriptions_device_id"); + + b.HasIndex("DeviceToken") + .IsUnique() + .HasDatabaseName("ix_notification_push_subscriptions_device_token"); + + b.ToTable("notification_push_subscriptions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("BackgroundId") + .HasColumnType("character varying(128)") + .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("FirstName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("first_name"); + + b.Property("LastName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("last_name"); + + b.Property("MiddleName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("middle_name"); + + b.Property("PictureId") + .HasColumnType("character varying(128)") + .HasColumnName("picture_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_profiles"); + + b.HasIndex("BackgroundId") + .HasDatabaseName("ix_account_profiles_background_id"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_account_profiles_picture_id"); + + b.ToTable("account_profiles", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => + { + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("RelatedId") + .HasColumnType("uuid") + .HasColumnName("related_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("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("AccountId", "RelatedId") + .HasName("pk_account_relationships"); + + b.HasIndex("RelatedId") + .HasDatabaseName("ix_account_relationships_related_id"); + + b.ToTable("account_relationships", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Status", 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("ClearedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("cleared_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("IsInvisible") + .HasColumnType("boolean") + .HasColumnName("is_invisible"); + + b.Property("IsNotDisturb") + .HasColumnType("boolean") + .HasColumnName("is_not_disturb"); + + b.Property("Label") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("label"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_statuses"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_statuses_account_id"); + + b.ToTable("account_statuses", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Activity.Activity", 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>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("ResourceIdentifier") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("resource_identifier"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property>("UsersVisible") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("users_visible"); + + b.Property("Visibility") + .HasColumnType("integer") + .HasColumnName("visibility"); + + b.HasKey("Id") + .HasName("pk_activities"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_activities_account_id"); + + b.ToTable("activities", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property>("Audiences") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("audiences"); + + b.Property>("BlacklistFactors") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("blacklist_factors"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("DeviceId") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("device_id"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("FailedAttempts") + .HasColumnType("integer") + .HasColumnName("failed_attempts"); + + b.Property("IpAddress") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("ip_address"); + + b.Property("Nonce") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("nonce"); + + b.Property("Platform") + .HasColumnType("integer") + .HasColumnName("platform"); + + b.Property>("Scopes") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("scopes"); + + b.Property("StepRemain") + .HasColumnType("integer") + .HasColumnName("step_remain"); + + b.Property("StepTotal") + .HasColumnType("integer") + .HasColumnName("step_total"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UserAgent") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("user_agent"); + + b.HasKey("Id") + .HasName("pk_auth_challenges"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_auth_challenges_account_id"); + + b.ToTable("auth_challenges", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("ChallengeId") + .HasColumnType("uuid") + .HasColumnName("challenge_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("Label") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("label"); + + b.Property("LastGrantedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_granted_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_auth_sessions"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_auth_sessions_account_id"); + + b.HasIndex("ChallengeId") + .HasDatabaseName("ix_auth_sessions_challenge_id"); + + b.ToTable("auth_sessions", (string)null); + }); + + 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("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("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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_chat_members"); + + b.HasAlternateKey("ChatRoomId", "AccountId") + .HasName("ak_chat_members_chat_room_id_account_id"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_chat_members_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("BackgroundId") + .HasColumnType("character varying(128)") + .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("IsPublic") + .HasColumnType("boolean") + .HasColumnName("is_public"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("PictureId") + .HasColumnType("character varying(128)") + .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("BackgroundId") + .HasDatabaseName("ix_chat_rooms_background_id"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_chat_rooms_picture_id"); + + 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("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() + .HasColumnType("text") + .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.MessageStatus", b => + { + b.Property("MessageId") + .HasColumnType("uuid") + .HasColumnName("message_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_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("ReadAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("read_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("MessageId", "SenderId") + .HasName("pk_chat_statuses"); + + b.HasIndex("SenderId") + .HasDatabaseName("ix_chat_statuses_sender_id"); + + b.ToTable("chat_statuses", (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("RoomId") + .HasColumnType("uuid") + .HasColumnName("room_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_id"); + + b.Property("Title") + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + 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.Permission.PermissionGroup", 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("Key") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("key"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_permission_groups"); + + b.ToTable("permission_groups", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b => + { + b.Property("GroupId") + .HasColumnType("uuid") + .HasColumnName("group_id"); + + b.Property("Actor") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("actor"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("GroupId", "Actor") + .HasName("pk_permission_group_members"); + + b.ToTable("permission_group_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Actor") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("actor"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + b.Property("Area") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("area"); + + 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("GroupId") + .HasColumnType("uuid") + .HasColumnName("group_id"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("key"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Value") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("value"); + + b.HasKey("Id") + .HasName("pk_permission_nodes"); + + b.HasIndex("GroupId") + .HasDatabaseName("ix_permission_nodes_group_id"); + + b.HasIndex("Key", "Area", "Actor") + .HasDatabaseName("ix_permission_nodes_key_area_actor"); + + b.ToTable("permission_nodes", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + 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("ThreadedPostId") + .HasColumnType("uuid") + .HasColumnName("threaded_post_id"); + + 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.HasIndex("ThreadedPostId") + .IsUnique() + .HasDatabaseName("ix_posts_threaded_post_id"); + + 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("AccountId") + .HasDatabaseName("ix_post_reactions_account_id"); + + 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.Post.Publisher", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("BackgroundId") + .HasColumnType("character varying(128)") + .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("PictureId") + .HasColumnType("character varying(128)") + .HasColumnName("picture_id"); + + b.Property("PublisherType") + .HasColumnType("integer") + .HasColumnName("publisher_type"); + + b.Property("RealmId") + .HasColumnType("uuid") + .HasColumnName("realm_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_publishers"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_publishers_account_id"); + + b.HasIndex("BackgroundId") + .HasDatabaseName("ix_publishers_background_id"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_publishers_name"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_publishers_picture_id"); + + b.HasIndex("RealmId") + .HasDatabaseName("ix_publishers_realm_id"); + + b.ToTable("publishers", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.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.HasIndex("AccountId") + .HasDatabaseName("ix_publisher_members_account_id"); + + b.ToTable("publisher_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.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("AccountId") + .HasDatabaseName("ix_publisher_subscriptions_account_id"); + + 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("BackgroundId") + .HasColumnType("character varying(128)") + .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("PictureId") + .HasColumnType("character varying(128)") + .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("VerifiedAs") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("verified_as"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + b.HasKey("Id") + .HasName("pk_realms"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_realms_account_id"); + + b.HasIndex("BackgroundId") + .HasDatabaseName("ix_realms_background_id"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_realms_picture_id"); + + 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("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.HasIndex("AccountId") + .HasDatabaseName("ix_realm_members_account_id"); + + b.ToTable("realm_members", (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("ImageId") + .IsRequired() + .HasColumnType("character varying(128)") + .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("ImageId") + .HasDatabaseName("ix_stickers_image_id"); + + b.HasIndex("PackId") + .HasDatabaseName("ix_stickers_pack_id"); + + 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("PublisherId") + .HasDatabaseName("ix_sticker_packs_publisher_id"); + + b.ToTable("sticker_packs", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => + { + b.Property("Id") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .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("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property>("FileMeta") + .HasColumnType("jsonb") + .HasColumnName("file_meta"); + + b.Property("HasCompression") + .HasColumnType("boolean") + .HasColumnName("has_compression"); + + b.Property("Hash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("hash"); + + b.Property("MessageId") + .HasColumnType("uuid") + .HasColumnName("message_id"); + + b.Property("MimeType") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("mime_type"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("PostId") + .HasColumnType("uuid") + .HasColumnName("post_id"); + + b.Property("Size") + .HasColumnType("bigint") + .HasColumnName("size"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UploadedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("uploaded_at"); + + b.Property("UploadedTo") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("uploaded_to"); + + b.Property("UsedCount") + .HasColumnType("integer") + .HasColumnName("used_count"); + + b.Property>("UserMeta") + .HasColumnType("jsonb") + .HasColumnName("user_meta"); + + b.HasKey("Id") + .HasName("pk_files"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_files_account_id"); + + b.HasIndex("MessageId") + .HasDatabaseName("ix_files_message_id"); + + b.HasIndex("PostId") + .HasDatabaseName("ix_files_post_id"); + + b.ToTable("files", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("PayeeWalletId") + .HasColumnType("uuid") + .HasColumnName("payee_wallet_id"); + + b.Property("Remarks") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("remarks"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("TransactionId") + .HasColumnType("uuid") + .HasColumnName("transaction_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_payment_orders"); + + b.HasIndex("PayeeWalletId") + .HasDatabaseName("ix_payment_orders_payee_wallet_id"); + + b.HasIndex("TransactionId") + .HasDatabaseName("ix_payment_orders_transaction_id"); + + b.ToTable("payment_orders", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PayeeWalletId") + .HasColumnType("uuid") + .HasColumnName("payee_wallet_id"); + + b.Property("PayerWalletId") + .HasColumnType("uuid") + .HasColumnName("payer_wallet_id"); + + b.Property("Remarks") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("remarks"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_payment_transactions"); + + b.HasIndex("PayeeWalletId") + .HasDatabaseName("ix_payment_transactions_payee_wallet_id"); + + b.HasIndex("PayerWalletId") + .HasDatabaseName("ix_payment_transactions_payer_wallet_id"); + + b.ToTable("payment_transactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_wallets"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_wallets_account_id"); + + b.ToTable("wallets", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.WalletPocket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("WalletId") + .HasColumnType("uuid") + .HasColumnName("wallet_id"); + + b.HasKey("Id") + .HasName("pk_wallet_pockets"); + + b.HasIndex("WalletId") + .HasDatabaseName("ix_wallet_pockets_wallet_id"); + + b.ToTable("wallet_pockets", (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.Account.AccountAuthFactor", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("AuthFactors") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_auth_factors_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Contacts") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_contacts_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Badge", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Badges") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_badges_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.CheckInResult", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_check_in_results_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .HasConstraintName("fk_magic_spells_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_notifications_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.NotificationPushSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_notification_push_subscriptions_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => + { + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_account_profiles_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithOne("Profile") + .HasForeignKey("DysonNetwork.Sphere.Account.Profile", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_profiles_accounts_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_account_profiles_files_picture_id"); + + b.Navigation("Account"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("OutgoingRelationships") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_relationships_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Account.Account", "Related") + .WithMany("IncomingRelationships") + .HasForeignKey("RelatedId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_relationships_accounts_related_id"); + + b.Navigation("Account"); + + b.Navigation("Related"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Status", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_statuses_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Activity.Activity", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_activities_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Challenges") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_auth_challenges_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Sessions") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_auth_sessions_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Auth.Challenge", "Challenge") + .WithMany() + .HasForeignKey("ChallengeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_auth_sessions_auth_challenges_challenge_id"); + + b.Navigation("Account"); + + b.Navigation("Challenge"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatMember", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_members_accounts_account_id"); + + 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("Account"); + + b.Navigation("ChatRoom"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_chat_rooms_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_chat_rooms_files_picture_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("ChatRooms") + .HasForeignKey("RealmId") + .HasConstraintName("fk_chat_rooms_realms_realm_id"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + + 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.MessageStatus", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.Message", "Message") + .WithMany("Statuses") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_statuses_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_statuses_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.Permission.PermissionGroupMember", b => + { + b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") + .WithMany("Members") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_permission_group_members_permission_groups_group_id"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => + { + b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") + .WithMany("Nodes") + .HasForeignKey("GroupId") + .HasConstraintName("fk_permission_nodes_permission_groups_group_id"); + + b.Navigation("Group"); + }); + + 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.Post.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.HasOne("DysonNetwork.Sphere.Post.Post", "ThreadedPost") + .WithOne() + .HasForeignKey("DysonNetwork.Sphere.Post.Post", "ThreadedPostId") + .HasConstraintName("fk_posts_posts_threaded_post_id"); + + b.Navigation("ForwardedPost"); + + b.Navigation("Publisher"); + + b.Navigation("RepliedPost"); + + b.Navigation("ThreadedPost"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => + { + b.HasOne("DysonNetwork.Sphere.Post.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.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", "Post") + .WithMany("Reactions") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_posts_post_id"); + + b.Navigation("Account"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .HasConstraintName("fk_publishers_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_publishers_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_publishers_files_picture_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany() + .HasForeignKey("RealmId") + .HasConstraintName("fk_publishers_realms_realm_id"); + + b.Navigation("Account"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + .WithMany("Members") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_publishers_publisher_id"); + + b.Navigation("Account"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + .WithMany("Subscriptions") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_publishers_publisher_id"); + + b.Navigation("Account"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realms_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_realms_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_realms_files_picture_id"); + + b.Navigation("Account"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_members_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("Members") + .HasForeignKey("RealmId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_members_realms_realm_id"); + + b.Navigation("Account"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b => + { + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_files_image_id"); + + b.HasOne("DysonNetwork.Sphere.Sticker.StickerPack", "Pack") + .WithMany() + .HasForeignKey("PackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_sticker_packs_pack_id"); + + b.Navigation("Image"); + + b.Navigation("Pack"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.StickerPack", b => + { + b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_sticker_packs_publishers_publisher_id"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_files_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.Message", null) + .WithMany("Attachments") + .HasForeignKey("MessageId") + .HasConstraintName("fk_files_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany("Attachments") + .HasForeignKey("PostId") + .HasConstraintName("fk_files_posts_post_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Order", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayeeWallet") + .WithMany() + .HasForeignKey("PayeeWalletId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_payment_orders_wallets_payee_wallet_id"); + + b.HasOne("DysonNetwork.Sphere.Wallet.Transaction", "Transaction") + .WithMany() + .HasForeignKey("TransactionId") + .HasConstraintName("fk_payment_orders_payment_transactions_transaction_id"); + + b.Navigation("PayeeWallet"); + + b.Navigation("Transaction"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Transaction", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayeeWallet") + .WithMany() + .HasForeignKey("PayeeWalletId") + .HasConstraintName("fk_payment_transactions_wallets_payee_wallet_id"); + + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayerWallet") + .WithMany() + .HasForeignKey("PayerWalletId") + .HasConstraintName("fk_payment_transactions_wallets_payer_wallet_id"); + + b.Navigation("PayeeWallet"); + + b.Navigation("PayerWallet"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_wallets_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.WalletPocket", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "Wallet") + .WithMany("Pockets") + .HasForeignKey("WalletId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_wallet_pockets_wallets_wallet_id"); + + b.Navigation("Wallet"); + }); + + 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.Account.Account", b => + { + b.Navigation("AuthFactors"); + + b.Navigation("Badges"); + + b.Navigation("Challenges"); + + b.Navigation("Contacts"); + + b.Navigation("IncomingRelationships"); + + b.Navigation("OutgoingRelationships"); + + b.Navigation("Profile") + .IsRequired(); + + b.Navigation("Sessions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", b => + { + b.Navigation("Attachments"); + + b.Navigation("Reactions"); + + b.Navigation("Statuses"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroup", b => + { + b.Navigation("Members"); + + b.Navigation("Nodes"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Navigation("Attachments"); + + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => + { + b.Navigation("Collections"); + + b.Navigation("Members"); + + b.Navigation("Posts"); + + b.Navigation("Subscriptions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b => + { + b.Navigation("ChatRooms"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b => + { + b.Navigation("Pockets"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/20250514142322_WalletAndPayment.cs b/DysonNetwork.Sphere/Migrations/20250514142322_WalletAndPayment.cs new file mode 100644 index 0000000..be88d80 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250514142322_WalletAndPayment.cs @@ -0,0 +1,168 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + /// + public partial class WalletAndPayment : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "wallets", + columns: table => new + { + 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_wallets", x => x.id); + table.ForeignKey( + name: "fk_wallets_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "payment_transactions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + currency = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + amount = table.Column(type: "numeric", nullable: false), + remarks = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + type = table.Column(type: "integer", nullable: false), + payer_wallet_id = table.Column(type: "uuid", nullable: true), + payee_wallet_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_payment_transactions", x => x.id); + table.ForeignKey( + name: "fk_payment_transactions_wallets_payee_wallet_id", + column: x => x.payee_wallet_id, + principalTable: "wallets", + principalColumn: "id"); + table.ForeignKey( + name: "fk_payment_transactions_wallets_payer_wallet_id", + column: x => x.payer_wallet_id, + principalTable: "wallets", + principalColumn: "id"); + }); + + migrationBuilder.CreateTable( + name: "wallet_pockets", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + currency = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + amount = table.Column(type: "numeric", nullable: false), + wallet_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_wallet_pockets", x => x.id); + table.ForeignKey( + name: "fk_wallet_pockets_wallets_wallet_id", + column: x => x.wallet_id, + principalTable: "wallets", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "payment_orders", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + status = table.Column(type: "integer", nullable: false), + currency = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + remarks = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + amount = table.Column(type: "numeric", nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: false), + payee_wallet_id = table.Column(type: "uuid", nullable: false), + transaction_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_payment_orders", x => x.id); + table.ForeignKey( + name: "fk_payment_orders_payment_transactions_transaction_id", + column: x => x.transaction_id, + principalTable: "payment_transactions", + principalColumn: "id"); + table.ForeignKey( + name: "fk_payment_orders_wallets_payee_wallet_id", + column: x => x.payee_wallet_id, + principalTable: "wallets", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_payment_orders_payee_wallet_id", + table: "payment_orders", + column: "payee_wallet_id"); + + migrationBuilder.CreateIndex( + name: "ix_payment_orders_transaction_id", + table: "payment_orders", + column: "transaction_id"); + + migrationBuilder.CreateIndex( + name: "ix_payment_transactions_payee_wallet_id", + table: "payment_transactions", + column: "payee_wallet_id"); + + migrationBuilder.CreateIndex( + name: "ix_payment_transactions_payer_wallet_id", + table: "payment_transactions", + column: "payer_wallet_id"); + + migrationBuilder.CreateIndex( + name: "ix_wallet_pockets_wallet_id", + table: "wallet_pockets", + column: "wallet_id"); + + migrationBuilder.CreateIndex( + name: "ix_wallets_account_id", + table: "wallets", + column: "account_id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "payment_orders"); + + migrationBuilder.DropTable( + name: "wallet_pockets"); + + migrationBuilder.DropTable( + name: "payment_transactions"); + + migrationBuilder.DropTable( + name: "wallets"); + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/20250514150441_PublisherFeatures.Designer.cs b/DysonNetwork.Sphere/Migrations/20250514150441_PublisherFeatures.Designer.cs new file mode 100644 index 0000000..92ed546 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250514150441_PublisherFeatures.Designer.cs @@ -0,0 +1,3209 @@ +// +using System; +using System.Collections.Generic; +using System.Text.Json; +using DysonNetwork.Sphere; +using DysonNetwork.Sphere.Account; +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("20250514150441_PublisherFeatures")] + partial class PublisherFeatures + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ActivatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("activated_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("IsSuperuser") + .HasColumnType("boolean") + .HasColumnName("is_superuser"); + + b.Property("Language") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("language"); + + 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_accounts"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_accounts_name"); + + b.ToTable("accounts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", 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("Secret") + .HasMaxLength(8196) + .HasColumnType("character varying(8196)") + .HasColumnName("secret"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_auth_factors"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_auth_factors_account_id"); + + b.ToTable("account_auth_factors", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .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("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + b.HasKey("Id") + .HasName("pk_account_contacts"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_contacts_account_id"); + + b.ToTable("account_contacts", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Badge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("Caption") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("caption"); + + 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("Label") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("label"); + + b.Property>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + 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_badges"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_badges_account_id"); + + b.ToTable("badges", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.CheckInResult", 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("Level") + .HasColumnType("integer") + .HasColumnName("level"); + + b.Property>("Tips") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("tips"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_check_in_results"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_check_in_results_account_id"); + + b.ToTable("account_check_in_results", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Spell") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("spell"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_magic_spells"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_magic_spells_account_id"); + + b.HasIndex("Spell") + .IsUnique() + .HasDatabaseName("ix_magic_spells_spell"); + + b.ToTable("magic_spells", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_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>("Meta") + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property("Subtitle") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("subtitle"); + + b.Property("Title") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("title"); + + b.Property("Topic") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("topic"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("ViewedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("viewed_at"); + + b.HasKey("Id") + .HasName("pk_notifications"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_notifications_account_id"); + + b.ToTable("notifications", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.NotificationPushSubscription", 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("DeviceId") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("device_id"); + + b.Property("DeviceToken") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("device_token"); + + b.Property("LastUsedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_used_at"); + + b.Property("Provider") + .HasColumnType("integer") + .HasColumnName("provider"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_notification_push_subscriptions"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_notification_push_subscriptions_account_id"); + + b.HasIndex("DeviceId") + .IsUnique() + .HasDatabaseName("ix_notification_push_subscriptions_device_id"); + + b.HasIndex("DeviceToken") + .IsUnique() + .HasDatabaseName("ix_notification_push_subscriptions_device_token"); + + b.ToTable("notification_push_subscriptions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("BackgroundId") + .HasColumnType("character varying(128)") + .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("FirstName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("first_name"); + + b.Property("LastName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("last_name"); + + b.Property("MiddleName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("middle_name"); + + b.Property("PictureId") + .HasColumnType("character varying(128)") + .HasColumnName("picture_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_profiles"); + + b.HasIndex("BackgroundId") + .HasDatabaseName("ix_account_profiles_background_id"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_account_profiles_picture_id"); + + b.ToTable("account_profiles", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => + { + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("RelatedId") + .HasColumnType("uuid") + .HasColumnName("related_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("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("AccountId", "RelatedId") + .HasName("pk_account_relationships"); + + b.HasIndex("RelatedId") + .HasDatabaseName("ix_account_relationships_related_id"); + + b.ToTable("account_relationships", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Status", 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("ClearedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("cleared_at"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("IsInvisible") + .HasColumnType("boolean") + .HasColumnName("is_invisible"); + + b.Property("IsNotDisturb") + .HasColumnType("boolean") + .HasColumnName("is_not_disturb"); + + b.Property("Label") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("label"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_account_statuses"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_account_statuses_account_id"); + + b.ToTable("account_statuses", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Activity.Activity", 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>("Meta") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("meta"); + + b.Property("ResourceIdentifier") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("resource_identifier"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property>("UsersVisible") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("users_visible"); + + b.Property("Visibility") + .HasColumnType("integer") + .HasColumnName("visibility"); + + b.HasKey("Id") + .HasName("pk_activities"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_activities_account_id"); + + b.ToTable("activities", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property>("Audiences") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("audiences"); + + b.Property>("BlacklistFactors") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("blacklist_factors"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("DeviceId") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("device_id"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("FailedAttempts") + .HasColumnType("integer") + .HasColumnName("failed_attempts"); + + b.Property("IpAddress") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("ip_address"); + + b.Property("Nonce") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("nonce"); + + b.Property("Platform") + .HasColumnType("integer") + .HasColumnName("platform"); + + b.Property>("Scopes") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("scopes"); + + b.Property("StepRemain") + .HasColumnType("integer") + .HasColumnName("step_remain"); + + b.Property("StepTotal") + .HasColumnType("integer") + .HasColumnName("step_total"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UserAgent") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("user_agent"); + + b.HasKey("Id") + .HasName("pk_auth_challenges"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_auth_challenges_account_id"); + + b.ToTable("auth_challenges", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + + b.Property("ChallengeId") + .HasColumnType("uuid") + .HasColumnName("challenge_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("Label") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("label"); + + b.Property("LastGrantedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_granted_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_auth_sessions"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_auth_sessions_account_id"); + + b.HasIndex("ChallengeId") + .HasDatabaseName("ix_auth_sessions_challenge_id"); + + b.ToTable("auth_sessions", (string)null); + }); + + 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("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("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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_chat_members"); + + b.HasAlternateKey("ChatRoomId", "AccountId") + .HasName("ak_chat_members_chat_room_id_account_id"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_chat_members_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("BackgroundId") + .HasColumnType("character varying(128)") + .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("IsPublic") + .HasColumnType("boolean") + .HasColumnName("is_public"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("PictureId") + .HasColumnType("character varying(128)") + .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("BackgroundId") + .HasDatabaseName("ix_chat_rooms_background_id"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_chat_rooms_picture_id"); + + 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("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() + .HasColumnType("text") + .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.MessageStatus", b => + { + b.Property("MessageId") + .HasColumnType("uuid") + .HasColumnName("message_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_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("ReadAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("read_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("MessageId", "SenderId") + .HasName("pk_chat_statuses"); + + b.HasIndex("SenderId") + .HasDatabaseName("ix_chat_statuses_sender_id"); + + b.ToTable("chat_statuses", (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("RoomId") + .HasColumnType("uuid") + .HasColumnName("room_id"); + + b.Property("SenderId") + .HasColumnType("uuid") + .HasColumnName("sender_id"); + + b.Property("Title") + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + 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("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(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + 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("VerifiedAs") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("verified_as"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + 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.Permission.PermissionGroup", 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("Key") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("key"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_permission_groups"); + + b.ToTable("permission_groups", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroupMember", b => + { + b.Property("GroupId") + .HasColumnType("uuid") + .HasColumnName("group_id"); + + b.Property("Actor") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("actor"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("GroupId", "Actor") + .HasName("pk_permission_group_members"); + + b.ToTable("permission_group_members", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Actor") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("actor"); + + b.Property("AffectedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("affected_at"); + + b.Property("Area") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("area"); + + 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("GroupId") + .HasColumnType("uuid") + .HasColumnName("group_id"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("key"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("Value") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("value"); + + b.HasKey("Id") + .HasName("pk_permission_nodes"); + + b.HasIndex("GroupId") + .HasDatabaseName("ix_permission_nodes_group_id"); + + b.HasIndex("Key", "Area", "Actor") + .HasDatabaseName("ix_permission_nodes_key_area_actor"); + + b.ToTable("permission_nodes", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + 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("ThreadedPostId") + .HasColumnType("uuid") + .HasColumnName("threaded_post_id"); + + 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.HasIndex("ThreadedPostId") + .IsUnique() + .HasDatabaseName("ix_posts_threaded_post_id"); + + 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("AccountId") + .HasDatabaseName("ix_post_reactions_account_id"); + + 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("BackgroundId") + .HasColumnType("character varying(128)") + .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("PictureId") + .HasColumnType("character varying(128)") + .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_publishers"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_publishers_account_id"); + + b.HasIndex("BackgroundId") + .HasDatabaseName("ix_publishers_background_id"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_publishers_name"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_publishers_picture_id"); + + 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.HasIndex("AccountId") + .HasDatabaseName("ix_publisher_members_account_id"); + + 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("AccountId") + .HasDatabaseName("ix_publisher_subscriptions_account_id"); + + 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("BackgroundId") + .HasColumnType("character varying(128)") + .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("PictureId") + .HasColumnType("character varying(128)") + .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("VerifiedAs") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("verified_as"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + b.HasKey("Id") + .HasName("pk_realms"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_realms_account_id"); + + b.HasIndex("BackgroundId") + .HasDatabaseName("ix_realms_background_id"); + + b.HasIndex("PictureId") + .HasDatabaseName("ix_realms_picture_id"); + + 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("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.HasIndex("AccountId") + .HasDatabaseName("ix_realm_members_account_id"); + + b.ToTable("realm_members", (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("ImageId") + .IsRequired() + .HasColumnType("character varying(128)") + .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("ImageId") + .HasDatabaseName("ix_stickers_image_id"); + + b.HasIndex("PackId") + .HasDatabaseName("ix_stickers_pack_id"); + + 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("PublisherId") + .HasDatabaseName("ix_sticker_packs_publisher_id"); + + b.ToTable("sticker_packs", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Storage.CloudFile", b => + { + b.Property("Id") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .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("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property>("FileMeta") + .HasColumnType("jsonb") + .HasColumnName("file_meta"); + + b.Property("HasCompression") + .HasColumnType("boolean") + .HasColumnName("has_compression"); + + b.Property("Hash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("hash"); + + b.Property("MessageId") + .HasColumnType("uuid") + .HasColumnName("message_id"); + + b.Property("MimeType") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("mime_type"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + b.Property("PostId") + .HasColumnType("uuid") + .HasColumnName("post_id"); + + b.Property("Size") + .HasColumnType("bigint") + .HasColumnName("size"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("UploadedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("uploaded_at"); + + b.Property("UploadedTo") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("uploaded_to"); + + b.Property("UsedCount") + .HasColumnType("integer") + .HasColumnName("used_count"); + + b.Property>("UserMeta") + .HasColumnType("jsonb") + .HasColumnName("user_meta"); + + b.HasKey("Id") + .HasName("pk_files"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_files_account_id"); + + b.HasIndex("MessageId") + .HasDatabaseName("ix_files_message_id"); + + b.HasIndex("PostId") + .HasDatabaseName("ix_files_post_id"); + + b.ToTable("files", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("PayeeWalletId") + .HasColumnType("uuid") + .HasColumnName("payee_wallet_id"); + + b.Property("Remarks") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("remarks"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("TransactionId") + .HasColumnType("uuid") + .HasColumnName("transaction_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_payment_orders"); + + b.HasIndex("PayeeWalletId") + .HasDatabaseName("ix_payment_orders_payee_wallet_id"); + + b.HasIndex("TransactionId") + .HasDatabaseName("ix_payment_orders_transaction_id"); + + b.ToTable("payment_orders", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PayeeWalletId") + .HasColumnType("uuid") + .HasColumnName("payee_wallet_id"); + + b.Property("PayerWalletId") + .HasColumnType("uuid") + .HasColumnName("payer_wallet_id"); + + b.Property("Remarks") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("remarks"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_payment_transactions"); + + b.HasIndex("PayeeWalletId") + .HasDatabaseName("ix_payment_transactions_payee_wallet_id"); + + b.HasIndex("PayerWalletId") + .HasDatabaseName("ix_payment_transactions_payer_wallet_id"); + + b.ToTable("payment_transactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_wallets"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_wallets_account_id"); + + b.ToTable("wallets", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.WalletPocket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("WalletId") + .HasColumnType("uuid") + .HasColumnName("wallet_id"); + + b.HasKey("Id") + .HasName("pk_wallet_pockets"); + + b.HasIndex("WalletId") + .HasDatabaseName("ix_wallet_pockets_wallet_id"); + + b.ToTable("wallet_pockets", (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.Account.AccountAuthFactor", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("AuthFactors") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_auth_factors_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountContact", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Contacts") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_contacts_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Badge", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Badges") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_badges_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.CheckInResult", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_check_in_results_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.MagicSpell", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .HasConstraintName("fk_magic_spells_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Notification", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_notifications_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.NotificationPushSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_notification_push_subscriptions_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => + { + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_account_profiles_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithOne("Profile") + .HasForeignKey("DysonNetwork.Sphere.Account.Profile", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_profiles_accounts_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_account_profiles_files_picture_id"); + + b.Navigation("Account"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("OutgoingRelationships") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_relationships_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Account.Account", "Related") + .WithMany("IncomingRelationships") + .HasForeignKey("RelatedId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_relationships_accounts_related_id"); + + b.Navigation("Account"); + + b.Navigation("Related"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Account.Status", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_account_statuses_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Activity.Activity", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_activities_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Challenges") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_auth_challenges_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Auth.Session", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany("Sessions") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_auth_sessions_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Auth.Challenge", "Challenge") + .WithMany() + .HasForeignKey("ChallengeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_auth_sessions_auth_challenges_challenge_id"); + + b.Navigation("Account"); + + b.Navigation("Challenge"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatMember", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_members_accounts_account_id"); + + 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("Account"); + + b.Navigation("ChatRoom"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_chat_rooms_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_chat_rooms_files_picture_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("ChatRooms") + .HasForeignKey("RealmId") + .HasConstraintName("fk_chat_rooms_realms_realm_id"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + + 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.MessageStatus", b => + { + b.HasOne("DysonNetwork.Sphere.Chat.Message", "Message") + .WithMany("Statuses") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_statuses_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.ChatMember", "Sender") + .WithMany() + .HasForeignKey("SenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chat_statuses_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.Permission.PermissionGroupMember", b => + { + b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") + .WithMany("Members") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_permission_group_members_permission_groups_group_id"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionNode", b => + { + b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") + .WithMany("Nodes") + .HasForeignKey("GroupId") + .HasConstraintName("fk_permission_nodes_permission_groups_group_id"); + + b.Navigation("Group"); + }); + + 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.HasOne("DysonNetwork.Sphere.Post.Post", "ThreadedPost") + .WithOne() + .HasForeignKey("DysonNetwork.Sphere.Post.Post", "ThreadedPostId") + .HasConstraintName("fk_posts_posts_threaded_post_id"); + + b.Navigation("ForwardedPost"); + + b.Navigation("Publisher"); + + b.Navigation("RepliedPost"); + + b.Navigation("ThreadedPost"); + }); + + 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.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", "Post") + .WithMany("Reactions") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_post_reactions_posts_post_id"); + + b.Navigation("Account"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .HasConstraintName("fk_publishers_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_publishers_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_publishers_files_picture_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany() + .HasForeignKey("RealmId") + .HasConstraintName("fk_publishers_realms_realm_id"); + + b.Navigation("Account"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherFeature", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany() + .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.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Members") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_members_publishers_publisher_id"); + + b.Navigation("Account"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherSubscription", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany("Subscriptions") + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_publisher_subscriptions_publishers_publisher_id"); + + b.Navigation("Account"); + + b.Navigation("Publisher"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realms_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Background") + .WithMany() + .HasForeignKey("BackgroundId") + .HasConstraintName("fk_realms_files_background_id"); + + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Picture") + .WithMany() + .HasForeignKey("PictureId") + .HasConstraintName("fk_realms_files_picture_id"); + + b.Navigation("Account"); + + b.Navigation("Background"); + + b.Navigation("Picture"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.RealmMember", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_members_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Realm.Realm", "Realm") + .WithMany("Members") + .HasForeignKey("RealmId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_realm_members_realms_realm_id"); + + b.Navigation("Account"); + + b.Navigation("Realm"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Sticker.Sticker", b => + { + b.HasOne("DysonNetwork.Sphere.Storage.CloudFile", "Image") + .WithMany() + .HasForeignKey("ImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_files_image_id"); + + b.HasOne("DysonNetwork.Sphere.Sticker.StickerPack", "Pack") + .WithMany() + .HasForeignKey("PackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_stickers_sticker_packs_pack_id"); + + b.Navigation("Image"); + + 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.Storage.CloudFile", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_files_accounts_account_id"); + + b.HasOne("DysonNetwork.Sphere.Chat.Message", null) + .WithMany("Attachments") + .HasForeignKey("MessageId") + .HasConstraintName("fk_files_chat_messages_message_id"); + + b.HasOne("DysonNetwork.Sphere.Post.Post", null) + .WithMany("Attachments") + .HasForeignKey("PostId") + .HasConstraintName("fk_files_posts_post_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Order", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayeeWallet") + .WithMany() + .HasForeignKey("PayeeWalletId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_payment_orders_wallets_payee_wallet_id"); + + b.HasOne("DysonNetwork.Sphere.Wallet.Transaction", "Transaction") + .WithMany() + .HasForeignKey("TransactionId") + .HasConstraintName("fk_payment_orders_payment_transactions_transaction_id"); + + b.Navigation("PayeeWallet"); + + b.Navigation("Transaction"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Transaction", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayeeWallet") + .WithMany() + .HasForeignKey("PayeeWalletId") + .HasConstraintName("fk_payment_transactions_wallets_payee_wallet_id"); + + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayerWallet") + .WithMany() + .HasForeignKey("PayerWalletId") + .HasConstraintName("fk_payment_transactions_wallets_payer_wallet_id"); + + b.Navigation("PayeeWallet"); + + b.Navigation("PayerWallet"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_wallets_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.WalletPocket", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "Wallet") + .WithMany("Pockets") + .HasForeignKey("WalletId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_wallet_pockets_wallets_wallet_id"); + + b.Navigation("Wallet"); + }); + + 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.Account.Account", b => + { + b.Navigation("AuthFactors"); + + b.Navigation("Badges"); + + b.Navigation("Challenges"); + + b.Navigation("Contacts"); + + b.Navigation("IncomingRelationships"); + + b.Navigation("OutgoingRelationships"); + + b.Navigation("Profile") + .IsRequired(); + + b.Navigation("Sessions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.ChatRoom", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Chat.Message", b => + { + b.Navigation("Attachments"); + + b.Navigation("Reactions"); + + b.Navigation("Statuses"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Permission.PermissionGroup", b => + { + b.Navigation("Members"); + + b.Navigation("Nodes"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Post.Post", b => + { + b.Navigation("Attachments"); + + b.Navigation("Reactions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => + { + b.Navigation("Collections"); + + b.Navigation("Members"); + + b.Navigation("Posts"); + + b.Navigation("Subscriptions"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Realm.Realm", b => + { + b.Navigation("ChatRooms"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b => + { + b.Navigation("Pockets"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/20250514150441_PublisherFeatures.cs b/DysonNetwork.Sphere/Migrations/20250514150441_PublisherFeatures.cs new file mode 100644 index 0000000..683571e --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250514150441_PublisherFeatures.cs @@ -0,0 +1,95 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + /// + public partial class PublisherFeatures : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "publisher_type", + table: "publishers", + newName: "type"); + + 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), + status = table.Column(type: "integer", nullable: false), + verified_at = table.Column(type: "timestamp with time zone", nullable: true), + verified_as = 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_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: "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.CreateIndex( + name: "ix_custom_apps_publisher_id", + table: "custom_apps", + column: "publisher_id"); + + migrationBuilder.CreateIndex( + name: "ix_publisher_features_publisher_id", + table: "publisher_features", + column: "publisher_id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "custom_apps"); + + migrationBuilder.DropTable( + name: "publisher_features"); + + migrationBuilder.RenameColumn( + name: "type", + table: "publishers", + newName: "publisher_type"); + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs index 2879600..9a93bfb 100644 --- a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs @@ -1140,6 +1140,63 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("chat_realtime_call", (string)null); }); + modelBuilder.Entity("DysonNetwork.Sphere.Developer.CustomApp", 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(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("name"); + + 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("VerifiedAs") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("verified_as"); + + b.Property("VerifiedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_at"); + + 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.Permission.PermissionGroup", b => { b.Property("Id") @@ -1565,7 +1622,7 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("post_tags", (string)null); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -1609,14 +1666,14 @@ namespace DysonNetwork.Sphere.Migrations .HasColumnType("character varying(128)") .HasColumnName("picture_id"); - b.Property("PublisherType") - .HasColumnType("integer") - .HasColumnName("publisher_type"); - 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"); @@ -1643,7 +1700,49 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("publishers", (string)null); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => + 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") @@ -1682,7 +1781,7 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("publisher_members", (string)null); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherSubscription", b => + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherSubscription", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -2049,6 +2148,200 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("files", (string)null); }); + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_at"); + + b.Property("PayeeWalletId") + .HasColumnType("uuid") + .HasColumnName("payee_wallet_id"); + + b.Property("Remarks") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("remarks"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("TransactionId") + .HasColumnType("uuid") + .HasColumnName("transaction_id"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_payment_orders"); + + b.HasIndex("PayeeWalletId") + .HasDatabaseName("ix_payment_orders_payee_wallet_id"); + + b.HasIndex("TransactionId") + .HasDatabaseName("ix_payment_orders_transaction_id"); + + b.ToTable("payment_orders", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("PayeeWalletId") + .HasColumnType("uuid") + .HasColumnName("payee_wallet_id"); + + b.Property("PayerWalletId") + .HasColumnType("uuid") + .HasColumnName("payer_wallet_id"); + + b.Property("Remarks") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("remarks"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_payment_transactions"); + + b.HasIndex("PayeeWalletId") + .HasDatabaseName("ix_payment_transactions_payee_wallet_id"); + + b.HasIndex("PayerWalletId") + .HasDatabaseName("ix_payment_transactions_payer_wallet_id"); + + b.ToTable("payment_transactions", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", 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("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id") + .HasName("pk_wallets"); + + b.HasIndex("AccountId") + .HasDatabaseName("ix_wallets_account_id"); + + b.ToTable("wallets", (string)null); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.WalletPocket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Amount") + .HasColumnType("numeric") + .HasColumnName("amount"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("currency"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.Property("WalletId") + .HasColumnType("uuid") + .HasColumnName("wallet_id"); + + b.HasKey("Id") + .HasName("pk_wallet_pockets"); + + b.HasIndex("WalletId") + .HasDatabaseName("ix_wallet_pockets_wallet_id"); + + b.ToTable("wallet_pockets", (string)null); + }); + modelBuilder.Entity("PostPostCategory", b => { b.Property("CategoriesId") @@ -2437,6 +2730,18 @@ namespace DysonNetwork.Sphere.Migrations 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.Permission.PermissionGroupMember", b => { b.HasOne("DysonNetwork.Sphere.Permission.PermissionGroup", "Group") @@ -2467,7 +2772,7 @@ namespace DysonNetwork.Sphere.Migrations .OnDelete(DeleteBehavior.Restrict) .HasConstraintName("fk_posts_posts_forwarded_post_id"); - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") .WithMany("Posts") .HasForeignKey("PublisherId") .OnDelete(DeleteBehavior.Cascade) @@ -2496,7 +2801,7 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Sphere.Post.PostCollection", b => { - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") .WithMany("Collections") .HasForeignKey("PublisherId") .OnDelete(DeleteBehavior.Cascade) @@ -2527,7 +2832,7 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Post"); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => { b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") .WithMany() @@ -2558,7 +2863,19 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Realm"); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherMember", b => + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherFeature", b => + { + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") + .WithMany() + .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.Account.Account", "Account") .WithMany() @@ -2567,7 +2884,7 @@ namespace DysonNetwork.Sphere.Migrations .IsRequired() .HasConstraintName("fk_publisher_members_accounts_account_id"); - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") .WithMany("Members") .HasForeignKey("PublisherId") .OnDelete(DeleteBehavior.Cascade) @@ -2579,7 +2896,7 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Publisher"); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.PublisherSubscription", b => + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.PublisherSubscription", b => { b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") .WithMany() @@ -2588,7 +2905,7 @@ namespace DysonNetwork.Sphere.Migrations .IsRequired() .HasConstraintName("fk_publisher_subscriptions_accounts_account_id"); - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") .WithMany("Subscriptions") .HasForeignKey("PublisherId") .OnDelete(DeleteBehavior.Cascade) @@ -2670,7 +2987,7 @@ namespace DysonNetwork.Sphere.Migrations modelBuilder.Entity("DysonNetwork.Sphere.Sticker.StickerPack", b => { - b.HasOne("DysonNetwork.Sphere.Post.Publisher", "Publisher") + b.HasOne("DysonNetwork.Sphere.Publisher.Publisher", "Publisher") .WithMany() .HasForeignKey("PublisherId") .OnDelete(DeleteBehavior.Cascade) @@ -2702,6 +3019,66 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Account"); }); + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Order", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayeeWallet") + .WithMany() + .HasForeignKey("PayeeWalletId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_payment_orders_wallets_payee_wallet_id"); + + b.HasOne("DysonNetwork.Sphere.Wallet.Transaction", "Transaction") + .WithMany() + .HasForeignKey("TransactionId") + .HasConstraintName("fk_payment_orders_payment_transactions_transaction_id"); + + b.Navigation("PayeeWallet"); + + b.Navigation("Transaction"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Transaction", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayeeWallet") + .WithMany() + .HasForeignKey("PayeeWalletId") + .HasConstraintName("fk_payment_transactions_wallets_payee_wallet_id"); + + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "PayerWallet") + .WithMany() + .HasForeignKey("PayerWalletId") + .HasConstraintName("fk_payment_transactions_wallets_payer_wallet_id"); + + b.Navigation("PayeeWallet"); + + b.Navigation("PayerWallet"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b => + { + b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_wallets_accounts_account_id"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.WalletPocket", b => + { + b.HasOne("DysonNetwork.Sphere.Wallet.Wallet", "Wallet") + .WithMany("Pockets") + .HasForeignKey("WalletId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_wallet_pockets_wallets_wallet_id"); + + b.Navigation("Wallet"); + }); + modelBuilder.Entity("PostPostCategory", b => { b.HasOne("DysonNetwork.Sphere.Post.PostCategory", null) @@ -2801,7 +3178,7 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Reactions"); }); - modelBuilder.Entity("DysonNetwork.Sphere.Post.Publisher", b => + modelBuilder.Entity("DysonNetwork.Sphere.Publisher.Publisher", b => { b.Navigation("Collections"); @@ -2818,6 +3195,11 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Members"); }); + + modelBuilder.Entity("DysonNetwork.Sphere.Wallet.Wallet", b => + { + b.Navigation("Pockets"); + }); #pragma warning restore 612, 618 } } diff --git a/DysonNetwork.Sphere/Post/Post.cs b/DysonNetwork.Sphere/Post/Post.cs index e07c105..f22a337 100644 --- a/DysonNetwork.Sphere/Post/Post.cs +++ b/DysonNetwork.Sphere/Post/Post.cs @@ -1,6 +1,5 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Text.Json; using System.Text.Json.Serialization; using DysonNetwork.Sphere.Storage; using NodaTime; @@ -55,7 +54,7 @@ public class Post : ModelBase [JsonIgnore] public NpgsqlTsVector SearchVector { get; set; } = null!; - public Publisher Publisher { get; set; } = null!; + public Publisher.Publisher Publisher { get; set; } = null!; public ICollection Reactions { get; set; } = new List(); public ICollection Tags { get; set; } = new List(); public ICollection Categories { get; set; } = new List(); @@ -88,7 +87,7 @@ public class PostCollection : ModelBase [MaxLength(256)] public string? Name { get; set; } [MaxLength(4096)] public string? Description { get; set; } - public Publisher Publisher { get; set; } = null!; + public Publisher.Publisher Publisher { get; set; } = null!; public ICollection Posts { get; set; } = new List(); } diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs index 849f2b0..d222712 100644 --- a/DysonNetwork.Sphere/Post/PostController.cs +++ b/DysonNetwork.Sphere/Post/PostController.cs @@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.Text.Json; using DysonNetwork.Sphere.Account; using DysonNetwork.Sphere.Permission; +using DysonNetwork.Sphere.Publisher; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -11,7 +12,13 @@ namespace DysonNetwork.Sphere.Post; [ApiController] [Route("/posts")] -public class PostController(AppDatabase db, PostService ps, RelationshipService rels, IServiceScopeFactory factory) +public class PostController( + AppDatabase db, + PostService ps, + PublisherService pub, + RelationshipService rels, + IServiceScopeFactory factory +) : ControllerBase { [HttpGet] @@ -21,14 +28,13 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); var currentUser = currentUserValue as Account.Account; var userFriends = currentUser is null ? [] : await rels.ListAccountFriends(currentUser); - - var publisher = pubName == null ? null : - await db.Publishers.FirstOrDefaultAsync(p => p.Name == pubName); - + + var publisher = pubName == null ? null : await db.Publishers.FirstOrDefaultAsync(p => p.Name == pubName); + var query = db.Posts.AsQueryable(); if (publisher != null) query = query.Where(p => p.Publisher.Id == publisher.Id); - + var totalCount = await query .FilterWithVisibility(currentUser, userFriends, isListing: true) .CountAsync(); @@ -150,12 +156,12 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); - Publisher? publisher; + Publisher.Publisher? publisher; if (publisherName is null) { // Use the first personal publisher publisher = await db.Publishers.FirstOrDefaultAsync(e => - e.AccountId == currentUser.Id && e.PublisherType == PublisherType.Individual); + e.AccountId == currentUser.Id && e.Type == PublisherType.Individual); } else { @@ -281,10 +287,7 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService .FirstOrDefaultAsync(); if (post is null) return NotFound(); - var member = await db.PublisherMembers - .FirstOrDefaultAsync(e => e.AccountId == currentUser.Id && e.PublisherId == post.Publisher.Id); - if (member is null) return StatusCode(403, "You even wasn't a member of the publisher you specified."); - if (member.Role < PublisherMemberRole.Editor) + if (!await pub.IsMemberWithRole(post.Publisher.Id, currentUser.Id, PublisherMemberRole.Editor)) return StatusCode(403, "You need at least be an editor to edit this publisher's post."); if (request.Title is not null) post.Title = request.Title; @@ -324,14 +327,10 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService .FirstOrDefaultAsync(); if (post is null) return NotFound(); - var member = await db.PublisherMembers - .FirstOrDefaultAsync(e => e.AccountId == currentUser.Id && e.PublisherId == post.Publisher.Id); - if (member is null) return StatusCode(403, "You even wasn't a member of the publisher you specified."); - if (member.Role < PublisherMemberRole.Editor) + if (!await pub.IsMemberWithRole(post.Publisher.Id, currentUser.Id, PublisherMemberRole.Editor)) return StatusCode(403, "You need at least be an editor to delete the publisher's post."); await ps.DeletePostAsync(post); - return NoContent(); } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Program.cs b/DysonNetwork.Sphere/Program.cs index ab195ff..7076338 100644 --- a/DysonNetwork.Sphere/Program.cs +++ b/DysonNetwork.Sphere/Program.cs @@ -14,9 +14,11 @@ using DysonNetwork.Sphere.Connection.Handlers; using DysonNetwork.Sphere.Localization; using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Post; +using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Realm; using DysonNetwork.Sphere.Sticker; using DysonNetwork.Sphere.Storage; +using DysonNetwork.Sphere.Wallet; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc; @@ -165,6 +167,8 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); // Timed task diff --git a/DysonNetwork.Sphere/Post/Publisher.cs b/DysonNetwork.Sphere/Publisher/Publisher.cs similarity index 81% rename from DysonNetwork.Sphere/Post/Publisher.cs rename to DysonNetwork.Sphere/Publisher/Publisher.cs index 9d06e68..4208176 100644 --- a/DysonNetwork.Sphere/Post/Publisher.cs +++ b/DysonNetwork.Sphere/Publisher/Publisher.cs @@ -1,11 +1,11 @@ using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; +using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Storage; using Microsoft.EntityFrameworkCore; using NodaTime; -namespace DysonNetwork.Sphere.Post; +namespace DysonNetwork.Sphere.Publisher; public enum PublisherType { @@ -17,7 +17,7 @@ public enum PublisherType public class Publisher : ModelBase { public Guid Id { get; set; } - public PublisherType PublisherType { get; set; } + public PublisherType Type { get; set; } [MaxLength(256)] public string Name { get; set; } = string.Empty; [MaxLength(256)] public string Nick { get; set; } = string.Empty; [MaxLength(4096)] public string? Bio { get; set; } @@ -27,7 +27,7 @@ public class Publisher : ModelBase public string? BackgroundId { get; set; } public CloudFile? Background { get; set; } - [JsonIgnore] public ICollection Posts { get; set; } = new List(); + [JsonIgnore] public ICollection Posts { get; set; } = new List(); [JsonIgnore] public ICollection Collections { get; set; } = new List(); [JsonIgnore] public ICollection Members { get; set; } = new List(); @@ -77,4 +77,14 @@ public class PublisherSubscription : ModelBase public SubscriptionStatus Status { get; set; } = SubscriptionStatus.Active; public int Tier { get; set; } = 0; +} + +public class PublisherFeature : ModelBase +{ + public Guid Id { get; set; } + [MaxLength(1024)] public string Flag { get; set; } = null!; + public Instant? ExpiredAt { get; set; } + + public Guid PublisherId { get; set; } + public Publisher Publisher { get; set; } = null!; } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Post/PublisherController.cs b/DysonNetwork.Sphere/Publisher/PublisherController.cs similarity index 93% rename from DysonNetwork.Sphere/Post/PublisherController.cs rename to DysonNetwork.Sphere/Publisher/PublisherController.cs index 5ca484e..b48a942 100644 --- a/DysonNetwork.Sphere/Post/PublisherController.cs +++ b/DysonNetwork.Sphere/Publisher/PublisherController.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using DysonNetwork.Sphere.Permission; +using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Realm; using DysonNetwork.Sphere.Storage; using Microsoft.AspNetCore.Authorization; @@ -7,7 +8,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NodaTime; -namespace DysonNetwork.Sphere.Post; +namespace DysonNetwork.Sphere.Publisher; [ApiController] [Route("/publishers")] @@ -15,7 +16,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic : ControllerBase { [HttpGet("{name}")] - public async Task> GetPublisher(string name) + public async Task> GetPublisher(string name) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); @@ -37,7 +38,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpGet] [Authorize] - public async Task>> ListManagedPublishers() + public async Task>> ListManagedPublishers() { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var userId = currentUser.Id; @@ -121,7 +122,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpPost("invites/{name}/accept")] [Authorize] - public async Task> AcceptMemberInvite(string name) + public async Task> AcceptMemberInvite(string name) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var userId = currentUser.Id; @@ -173,7 +174,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpPost("individual")] [Authorize] [RequiredPermission("global", "publishers.create")] - public async Task> CreatePublisherIndividual([FromBody] PublisherRequest request) + public async Task> CreatePublisherIndividual([FromBody] PublisherRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); @@ -217,7 +218,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpPost("organization/{realmSlug}")] [Authorize] [RequiredPermission("global", "publishers.create")] - public async Task> CreatePublisherOrganization(string realmSlug, [FromBody] PublisherRequest request) + public async Task> CreatePublisherOrganization(string realmSlug, [FromBody] PublisherRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); @@ -265,7 +266,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpPatch("{name}")] [Authorize] - public async Task> UpdatePublisher(string name, PublisherRequest request) + public async Task> UpdatePublisher(string name, PublisherRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var userId = currentUser.Id; @@ -316,7 +317,7 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic [HttpDelete("{name}")] [Authorize] - public async Task> DeletePublisher(string name) + public async Task> DeletePublisher(string name) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var userId = currentUser.Id; diff --git a/DysonNetwork.Sphere/Post/PublisherService.cs b/DysonNetwork.Sphere/Publisher/PublisherService.cs similarity index 69% rename from DysonNetwork.Sphere/Post/PublisherService.cs rename to DysonNetwork.Sphere/Publisher/PublisherService.cs index 8bd6c09..d8e0a7f 100644 --- a/DysonNetwork.Sphere/Post/PublisherService.cs +++ b/DysonNetwork.Sphere/Publisher/PublisherService.cs @@ -1,9 +1,10 @@ +using DysonNetwork.Sphere.Post; using DysonNetwork.Sphere.Storage; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using NodaTime; -namespace DysonNetwork.Sphere.Post; +namespace DysonNetwork.Sphere.Publisher; public class PublisherService(AppDatabase db, FileService fs, IMemoryCache cache) { @@ -18,7 +19,7 @@ public class PublisherService(AppDatabase db, FileService fs, IMemoryCache cache { var publisher = new Publisher { - PublisherType = PublisherType.Individual, + Type = PublisherType.Individual, Name = name ?? account.Name, Nick = nick ?? account.Nick, Bio = bio ?? account.Profile.Bio, @@ -57,7 +58,7 @@ public class PublisherService(AppDatabase db, FileService fs, IMemoryCache cache { var publisher = new Publisher { - PublisherType = PublisherType.Organizational, + Type = PublisherType.Organizational, Name = name ?? realm.Slug, Nick = nick ?? realm.Name, Bio = bio ?? realm.Description, @@ -95,6 +96,7 @@ public class PublisherService(AppDatabase db, FileService fs, IMemoryCache cache } private const string PublisherStatsCacheKey = "PublisherStats_{0}"; + private const string PublisherFeatureCacheKey = "PublisherFeature_{0}_{1}"; public async Task GetPublisherStats(string name) { @@ -134,4 +136,56 @@ public class PublisherService(AppDatabase db, FileService fs, IMemoryCache cache cache.Set(cacheKey, stats, TimeSpan.FromMinutes(5)); return stats; } + + public async Task SetFeatureFlag(Guid publisherId, string flag) + { + var featureFlag = await db.PublisherFeatures + .FirstOrDefaultAsync(f => f.PublisherId == publisherId && f.Flag == flag); + + if (featureFlag == null) + { + featureFlag = new PublisherFeature + { + PublisherId = publisherId, + Flag = flag, + }; + db.PublisherFeatures.Add(featureFlag); + } + else + { + featureFlag.ExpiredAt = SystemClock.Instance.GetCurrentInstant(); + } + + await db.SaveChangesAsync(); + cache.Remove(string.Format(PublisherFeatureCacheKey, publisherId, flag)); + } + + public async Task HasFeature(Guid publisherId, string flag) + { + var cacheKey = string.Format(PublisherFeatureCacheKey, publisherId, flag); + + if (cache.TryGetValue(cacheKey, out bool isEnabled)) + return isEnabled; + + var now = SystemClock.Instance.GetCurrentInstant(); + var featureFlag = await db.PublisherFeatures + .FirstOrDefaultAsync(f => + f.PublisherId == publisherId && f.Flag == flag && + (f.ExpiredAt == null || f.ExpiredAt > now) + ); + if (featureFlag is not null) isEnabled = true; + + cache.Set(cacheKey, isEnabled, TimeSpan.FromMinutes(5)); + return isEnabled; + } + + public async Task IsMemberWithRole(Guid publisherId, Guid accountId, PublisherMemberRole requiredRole) + { + var member = await db.Publishers + .Where(p => p.Id == publisherId) + .SelectMany(p => p.Members) + .FirstOrDefaultAsync(m => m.AccountId == accountId); + + return member != null && member.Role >= requiredRole; + } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Post/PublisherSubscriptionController.cs b/DysonNetwork.Sphere/Publisher/PublisherSubscriptionController.cs similarity index 98% rename from DysonNetwork.Sphere/Post/PublisherSubscriptionController.cs rename to DysonNetwork.Sphere/Publisher/PublisherSubscriptionController.cs index ef74d29..97c225e 100644 --- a/DysonNetwork.Sphere/Post/PublisherSubscriptionController.cs +++ b/DysonNetwork.Sphere/Publisher/PublisherSubscriptionController.cs @@ -1,8 +1,9 @@ +using DysonNetwork.Sphere.Post; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -namespace DysonNetwork.Sphere.Post; +namespace DysonNetwork.Sphere.Publisher; [ApiController] [Route("/publishers")] diff --git a/DysonNetwork.Sphere/Post/PublisherSubscriptionService.cs b/DysonNetwork.Sphere/Publisher/PublisherSubscriptionService.cs similarity index 98% rename from DysonNetwork.Sphere/Post/PublisherSubscriptionService.cs rename to DysonNetwork.Sphere/Publisher/PublisherSubscriptionService.cs index 6fd9155..3bc4a79 100644 --- a/DysonNetwork.Sphere/Post/PublisherSubscriptionService.cs +++ b/DysonNetwork.Sphere/Publisher/PublisherSubscriptionService.cs @@ -1,8 +1,7 @@ using DysonNetwork.Sphere.Account; using Microsoft.EntityFrameworkCore; -using NodaTime; -namespace DysonNetwork.Sphere.Post; +namespace DysonNetwork.Sphere.Publisher; public class PublisherSubscriptionService(AppDatabase db, NotificationService nty) { @@ -38,7 +37,7 @@ public class PublisherSubscriptionService(AppDatabase db, NotificationService nt /// /// The new post /// The number of subscribers notified - public async Task NotifySubscribersPostAsync(Post post) + public async Task NotifySubscribersPostAsync(Post.Post post) { var subscribers = await db.PublisherSubscriptions .Include(ps => ps.Account) diff --git a/DysonNetwork.Sphere/Realm/RealmChatController.cs b/DysonNetwork.Sphere/Realm/RealmChatController.cs index ab0dfcf..7e7795e 100644 --- a/DysonNetwork.Sphere/Realm/RealmChatController.cs +++ b/DysonNetwork.Sphere/Realm/RealmChatController.cs @@ -7,7 +7,7 @@ namespace DysonNetwork.Sphere.Realm; [ApiController] [Route("/realm/{slug}")] -public class RealmChatController(AppDatabase db) : ControllerBase +public class RealmChatController(AppDatabase db, RealmService rs) : ControllerBase { [HttpGet("chat")] [Authorize] @@ -22,17 +22,14 @@ public class RealmChatController(AppDatabase db) : ControllerBase if (!realm.IsPublic) { if (currentUser is null) return Unauthorized(); - var member = await db.ChatMembers - .Where(m => m.ChatRoomId == realm.Id) - .Where(m => m.AccountId == currentUser.Id) - .FirstOrDefaultAsync(); - if (member is null) return BadRequest("You need at least one member to view the realm's chat."); + if (!await rs.IsMemberWithRole(realm.Id, currentUser.Id, RealmMemberRole.Normal)) + return StatusCode(403, "You need at least one member to view the realm's chat."); } var chatRooms = await db.ChatRooms .Where(c => c.RealmId == realm.Id) .ToListAsync(); - + return Ok(chatRooms); } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Realm/RealmController.cs b/DysonNetwork.Sphere/Realm/RealmController.cs index c0cfdb2..c4308fc 100644 --- a/DysonNetwork.Sphere/Realm/RealmController.cs +++ b/DysonNetwork.Sphere/Realm/RealmController.cs @@ -78,15 +78,7 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) : .FirstOrDefaultAsync(); if (realm is null) return NotFound(); - var member = await db.RealmMembers - .Where(m => m.AccountId == userId) - .Where(m => m.RealmId == realm.Id) - .FirstOrDefaultAsync(); - if (member is null) return StatusCode(403, "You are not even a member of the targeted realm."); - if (member.Role < RealmMemberRole.Moderator) - return StatusCode(403, - "You need at least be a manager to invite other members to collaborate this realm."); - if (member.Role < request.Role) + if (!await rs.IsMemberWithRole(realm.Id, userId, request.Role)) return StatusCode(403, "You cannot invite member has higher permission than yours."); var newMember = new RealmMember @@ -145,8 +137,8 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) : return NoContent(); } - - + + [HttpGet("{slug}/members")] public async Task>> ListMembers( string slug, @@ -162,9 +154,8 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) : if (!realm.IsPublic) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); - var isMember = await db.RealmMembers - .AnyAsync(m => m.AccountId == currentUser.Id && m.RealmId == realm.Id && m.JoinedAt != null); - if (!isMember) return StatusCode(403, "You must be a member to view this realm's members."); + if (!await rs.IsMemberWithRole(realm.Id, currentUser.Id, RealmMemberRole.Normal)) + return StatusCode(403, "You must be a member to view this realm's members."); } var query = db.RealmMembers @@ -191,14 +182,14 @@ public class RealmController(AppDatabase db, RealmService rs, FileService fs) : { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var userId = currentUser.Id; - + var member = await db.RealmMembers .Where(m => m.AccountId == userId) .Where(m => m.Realm.Slug == slug) .Include(m => m.Account) .Include(m => m.Account.Profile) .FirstOrDefaultAsync(); - + if (member is null) return NotFound(); return Ok(member); } diff --git a/DysonNetwork.Sphere/Realm/RealmService.cs b/DysonNetwork.Sphere/Realm/RealmService.cs index cf5d2e6..4e4c988 100644 --- a/DysonNetwork.Sphere/Realm/RealmService.cs +++ b/DysonNetwork.Sphere/Realm/RealmService.cs @@ -1,4 +1,5 @@ using DysonNetwork.Sphere.Account; +using Microsoft.EntityFrameworkCore; namespace DysonNetwork.Sphere.Realm; @@ -9,4 +10,11 @@ public class RealmService(AppDatabase db, NotificationService nty) await nty.SendNotification(member.Account, "invites.realms", "New Realm Invitation", null, $"You just got invited to join {member.Realm.Name}"); } + + public async Task IsMemberWithRole(Guid realmId, Guid accountId, RealmMemberRole requiredRole) + { + var member = await db.RealmMembers + .FirstOrDefaultAsync(m => m.RealmId == realmId && m.AccountId == accountId); + return member?.Role >= requiredRole; + } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Sticker/Sticker.cs b/DysonNetwork.Sphere/Sticker/Sticker.cs index 54cbad7..7e4e125 100644 --- a/DysonNetwork.Sphere/Sticker/Sticker.cs +++ b/DysonNetwork.Sphere/Sticker/Sticker.cs @@ -23,6 +23,6 @@ public class StickerPack : ModelBase [MaxLength(128)] public string Prefix { get; set; } = null!; public Guid PublisherId { get; set; } - public Post.Publisher Publisher { get; set; } = null!; + public Publisher.Publisher Publisher { get; set; } = null!; } diff --git a/DysonNetwork.Sphere/Sticker/StickerController.cs b/DysonNetwork.Sphere/Sticker/StickerController.cs index cfe2a34..ce1732f 100644 --- a/DysonNetwork.Sphere/Sticker/StickerController.cs +++ b/DysonNetwork.Sphere/Sticker/StickerController.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations; using DysonNetwork.Sphere.Permission; using DysonNetwork.Sphere.Post; +using DysonNetwork.Sphere.Publisher; using DysonNetwork.Sphere.Storage; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; diff --git a/DysonNetwork.Sphere/Wallet/Payment.cs b/DysonNetwork.Sphere/Wallet/Payment.cs new file mode 100644 index 0000000..0b5e53c --- /dev/null +++ b/DysonNetwork.Sphere/Wallet/Payment.cs @@ -0,0 +1,51 @@ +using System.ComponentModel.DataAnnotations; +using NodaTime; + +namespace DysonNetwork.Sphere.Wallet; + +public enum OrderStatus +{ + Unpaid, + Paid, + Cancelled, + Finished, + Expired +} + +public class Order : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public OrderStatus Status { get; set; } = OrderStatus.Unpaid; + [MaxLength(128)] public string Currency { get; set; } = null!; + [MaxLength(4096)] public string? Remarks { get; set; } + public decimal Amount { get; set; } + public Instant ExpiredAt { get; set; } + + public Guid PayeeWalletId { get; set; } + public Wallet PayeeWallet { get; set; } = null!; + public Guid? TransactionId { get; set; } + public Transaction? Transaction { get; set; } +} + +public enum TransactionType +{ + System, + Transfer, + Order +} + +public class Transaction : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + [MaxLength(128)] public string Currency { get; set; } = null!; + public decimal Amount { get; set; } + [MaxLength(4096)] public string? Remarks { get; set; } + public TransactionType Type { get; set; } + + // When the payer is null, it's pay from the system + public Guid? PayerWalletId { get; set; } + public Wallet? PayerWallet { get; set; } + // When the payee is null, it's pay for the system + public Guid? PayeeWalletId { get; set; } + public Wallet? PayeeWallet { get; set; } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Wallet/PaymentService.cs b/DysonNetwork.Sphere/Wallet/PaymentService.cs new file mode 100644 index 0000000..51e840a --- /dev/null +++ b/DysonNetwork.Sphere/Wallet/PaymentService.cs @@ -0,0 +1,184 @@ +using Microsoft.EntityFrameworkCore; +using NodaTime; + +namespace DysonNetwork.Sphere.Wallet; + +public class PaymentService(AppDatabase db, WalletService wat) +{ + public async Task CreateOrderAsync(Guid payeeWalletId, string currency, decimal amount, Duration expiration) + { + var order = new Order + { + PayeeWalletId = payeeWalletId, + Currency = currency, + Amount = amount, + ExpiredAt = SystemClock.Instance.GetCurrentInstant().Plus(expiration) + }; + + db.PaymentOrders.Add(order); + await db.SaveChangesAsync(); + return order; + } + + public async Task CreateTransactionAsync( + Guid? payerWalletId, + Guid? payeeWalletId, + string currency, + decimal amount, + string? remarks = null, + TransactionType type = TransactionType.System + ) + { + var transaction = new Transaction + { + PayerWalletId = payerWalletId, + PayeeWalletId = payeeWalletId, + Currency = currency, + Amount = amount, + Remarks = remarks, + Type = type + }; + + if (payerWalletId.HasValue) + { + var payerPocket = await wat.GetOrCreateWalletPocketAsync( + (await db.Wallets.FindAsync(payerWalletId.Value))!.AccountId, + currency); + + if (payerPocket.Amount < amount) + { + throw new InvalidOperationException("Insufficient funds"); + } + + payerPocket.Amount -= amount; + } + + if (payeeWalletId.HasValue) + { + var payeeWallet = await db.Wallets.FindAsync(payeeWalletId.Value); + var payeePocket = await wat.GetOrCreateWalletPocketAsync( + payeeWallet!.AccountId, + currency); + + payeePocket.Amount += amount; + } + + db.PaymentTransactions.Add(transaction); + await db.SaveChangesAsync(); + return transaction; + } + + public async Task PayOrderAsync(Guid orderId, Guid payerWalletId) + { + var order = await db.PaymentOrders + .Include(o => o.Transaction) + .FirstOrDefaultAsync(o => o.Id == orderId); + + if (order == null) + { + throw new InvalidOperationException("Order not found"); + } + + if (order.Status != OrderStatus.Unpaid) + { + throw new InvalidOperationException($"Order is in invalid status: {order.Status}"); + } + + if (order.ExpiredAt < SystemClock.Instance.GetCurrentInstant()) + { + order.Status = OrderStatus.Expired; + await db.SaveChangesAsync(); + throw new InvalidOperationException("Order has expired"); + } + + var transaction = await CreateTransactionAsync( + payerWalletId, + order.PayeeWalletId, + order.Currency, + order.Amount, + order.Remarks ?? $"Payment for Order #{order.Id}", + type: TransactionType.Order); + + order.TransactionId = transaction.Id; + order.Transaction = transaction; + order.Status = OrderStatus.Paid; + + await db.SaveChangesAsync(); + return order; + } + + public async Task CancelOrderAsync(Guid orderId) + { + var order = await db.PaymentOrders.FindAsync(orderId); + if (order == null) + { + throw new InvalidOperationException("Order not found"); + } + + if (order.Status != OrderStatus.Unpaid) + { + throw new InvalidOperationException($"Cannot cancel order in status: {order.Status}"); + } + + order.Status = OrderStatus.Cancelled; + await db.SaveChangesAsync(); + return order; + } + + public async Task<(Order Order, Transaction RefundTransaction)> RefundOrderAsync(Guid orderId) + { + var order = await db.PaymentOrders + .Include(o => o.Transaction) + .FirstOrDefaultAsync(o => o.Id == orderId); + + if (order == null) + { + throw new InvalidOperationException("Order not found"); + } + + if (order.Status != OrderStatus.Paid) + { + throw new InvalidOperationException($"Cannot refund order in status: {order.Status}"); + } + + if (order.Transaction == null) + { + throw new InvalidOperationException("Order has no associated transaction"); + } + + var refundTransaction = await CreateTransactionAsync( + order.PayeeWalletId, + order.Transaction.PayerWalletId, + order.Currency, + order.Amount, + $"Refund for order {order.Id}"); + + order.Status = OrderStatus.Finished; + await db.SaveChangesAsync(); + + return (order, refundTransaction); + } + + public async Task TransferAsync(Guid payerAccountId, Guid payeeAccountId, string currency, decimal amount) + { + var payerWallet = await wat.GetWalletAsync(payerAccountId); + if (payerWallet == null) + { + throw new InvalidOperationException($"Payer wallet not found for account {payerAccountId}"); + } + + var payeeWallet = await wat.GetWalletAsync(payeeAccountId); + if (payeeWallet == null) + { + throw new InvalidOperationException($"Payee wallet not found for account {payeeAccountId}"); + } + + return await CreateTransactionAsync( + payerWallet.Id, + payeeWallet.Id, + currency, + amount, + $"Transfer from account {payerAccountId} to {payeeAccountId}", + TransactionType.Transfer); + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Wallet/Wallet.cs b/DysonNetwork.Sphere/Wallet/Wallet.cs new file mode 100644 index 0000000..5d25972 --- /dev/null +++ b/DysonNetwork.Sphere/Wallet/Wallet.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; + +namespace DysonNetwork.Sphere.Wallet; + +public class Wallet : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + + public ICollection Pockets { get; set; } = new List(); + + public Guid AccountId { get; set; } + public Account.Account Account { get; set; } = null!; +} + +public class WalletPocket : ModelBase +{ + public Guid Id { get; set; } = Guid.NewGuid(); + [MaxLength(128)] public string Currency { get; set; } = null!; + public decimal Amount { get; set; } + + public Guid WalletId { get; set; } + public Wallet Wallet { get; set; } = null!; +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Wallet/WalletService.cs b/DysonNetwork.Sphere/Wallet/WalletService.cs new file mode 100644 index 0000000..d635601 --- /dev/null +++ b/DysonNetwork.Sphere/Wallet/WalletService.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore; + +namespace DysonNetwork.Sphere.Wallet; + +public class WalletService(AppDatabase db) +{ + public async Task GetWalletAsync(Guid accountId) + { + return await db.Wallets + .Include(w => w.Pockets) + .FirstOrDefaultAsync(w => w.AccountId == accountId); + } + + public async Task CreateWalletAsync(Guid accountId) + { + var wallet = new Wallet + { + AccountId = accountId + }; + + db.Wallets.Add(wallet); + await db.SaveChangesAsync(); + + return wallet; + } + + public async Task GetOrCreateWalletPocketAsync(Guid accountId, string currency) + { + var wallet = await db.Wallets + .Include(w => w.Pockets) + .FirstOrDefaultAsync(w => w.AccountId == accountId); + + if (wallet == null) + { + throw new InvalidOperationException($"Wallet not found for account {accountId}"); + } + + var pocket = wallet.Pockets.FirstOrDefault(p => p.Currency == currency); + + if (pocket != null) return pocket; + + pocket = new WalletPocket + { + Currency = currency, + Amount = 0, + WalletId = wallet.Id + }; + + wallet.Pockets.Add(pocket); + await db.SaveChangesAsync(); + + return pocket; + } +} \ No newline at end of file