diff --git a/DysonNetwork.Sphere/Account/Account.cs b/DysonNetwork.Sphere/Account/Account.cs index ee53561..ffadf74 100644 --- a/DysonNetwork.Sphere/Account/Account.cs +++ b/DysonNetwork.Sphere/Account/Account.cs @@ -12,6 +12,7 @@ public class Account : BaseModel [MaxLength(32)] public string Language { get; set; } = string.Empty; public bool IsSuperuser { get; set; } = false; + public Profile Profile { get; set; } = null!; public ICollection Contacts { get; set; } = new List(); [JsonIgnore] public ICollection AuthFactors { get; set; } = new List(); @@ -19,6 +20,20 @@ public class Account : BaseModel [JsonIgnore] public ICollection Challenges { get; set; } = new List(); } +public class Profile : BaseModel +{ + public long Id { get; set; } + [MaxLength(256)] public string? FirstName { get; set; } + [MaxLength(256)] public string? MiddleName { get; set; } + [MaxLength(256)] public string? LastName { get; set; } + [MaxLength(4096)] public string? Bio { get; set; } + + public Storage.CloudFile? Picture { get; set; } + public Storage.CloudFile? Background { get; set; } + + [JsonIgnore] public Account Account { get; set; } = null!; +} + public class AccountContact : BaseModel { public long Id { get; set; } diff --git a/DysonNetwork.Sphere/Account/AccountController.cs b/DysonNetwork.Sphere/Account/AccountController.cs index 5ee64ad..9b8f281 100644 --- a/DysonNetwork.Sphere/Account/AccountController.cs +++ b/DysonNetwork.Sphere/Account/AccountController.cs @@ -7,7 +7,7 @@ namespace DysonNetwork.Sphere.Account; [ApiController] [Route("/accounts")] -public class AccountController(AppDatabase db, IHttpContextAccessor httpContext) : ControllerBase +public class AccountController(AppDatabase db) : ControllerBase { [HttpGet("{name}")] [ProducesResponseType(StatusCodes.Status200OK)] @@ -22,7 +22,11 @@ public class AccountController(AppDatabase db, IHttpContextAccessor httpContext) { [Required] [MaxLength(256)] public string Name { get; set; } = string.Empty; [Required] [MaxLength(256)] public string Nick { get; set; } = string.Empty; - [Required] [MaxLength(1024)] public string Email { get; set; } = string.Empty; + + [EmailAddress] + [Required] + [MaxLength(1024)] + public string Email { get; set; } = string.Empty; [Required] [MinLength(4)] @@ -58,25 +62,116 @@ public class AccountController(AppDatabase db, IHttpContextAccessor httpContext) Type = AccountAuthFactorType.Password, Secret = request.Password }.HashSecret() - } + }, + Profile = new Profile() }; await db.Accounts.AddAsync(account); await db.SaveChangesAsync(); return account; } - + [Authorize] [HttpGet("me")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetMe() { - var userIdClaim = httpContext.HttpContext?.User.FindFirst("user_id")?.Value; + var userIdClaim = User.FindFirst("user_id")?.Value; + long? userId = long.TryParse(userIdClaim, out var id) ? id : null; + if (userId is null) return new BadRequestObjectResult("Invalid or missing user_id claim."); + + var account = await db.Accounts + .Include(e => e.Profile) + .Where(e => e.Id == userId) + .FirstOrDefaultAsync(); + + return Ok(account); + } + + public class BasicInfoRequest + { + [MaxLength(256)] public string? Nick { get; set; } + [MaxLength(32)] public string? Language { get; set; } + } + + [Authorize] + [HttpPatch("me")] + public async Task> UpdateBasicInfo([FromBody] BasicInfoRequest request) + { + var userIdClaim = User.FindFirst("user_id")?.Value; long? userId = long.TryParse(userIdClaim, out var id) ? id : null; if (userId is null) return new BadRequestObjectResult("Invalid or missing user_id claim."); var account = await db.Accounts.FindAsync(userId); + if (account is null) return BadRequest("Unable to get your account."); - return Ok(account); + if (request.Nick is not null) account.Nick = request.Nick; + if (request.Language is not null) account.Language = request.Language; + + await db.SaveChangesAsync(); + return account; + } + + public class ProfileRequest + { + [MaxLength(256)] public string? FirstName { get; set; } + [MaxLength(256)] public string? MiddleName { get; set; } + [MaxLength(256)] public string? LastName { get; set; } + [MaxLength(4096)] public string? Bio { get; set; } + + public string? PictureId { get; set; } + public string? BackgroundId { get; set; } + } + + [Authorize] + [HttpPatch("me/profile")] + public async Task> UpdateProfile([FromBody] ProfileRequest request) + { + var userIdClaim = User.FindFirst("user_id")?.Value; + long? userId = long.TryParse(userIdClaim, out var id) ? id : null; + if (userId is null) return new BadRequestObjectResult("Invalid or missing user_id claim."); + + var profile = await db.AccountProfiles + .Where(p => p.Account.Id == userId) + .Include(profile => profile.Background) + .Include(profile => profile.Picture) + .FirstOrDefaultAsync(); + if (profile is null) return BadRequest("Unable to get your account."); + + if (request.FirstName is not null) profile.FirstName = request.FirstName; + if (request.MiddleName is not null) profile.MiddleName = request.MiddleName; + if (request.LastName is not null) profile.LastName = request.LastName; + if (request.Bio is not null) profile.Bio = request.Bio; + + if (request.PictureId is not null) + { + var picture = await db.Files.Where(f => f.Id == request.PictureId).FirstOrDefaultAsync(); + if (picture is null) return BadRequest("Invalid picture id, unable to find the file on cloud."); + if (profile.Picture is not null) + { + profile.Picture.UsedCount--; + db.Update(profile.Picture); + } + + picture.UsedCount++; + profile.Picture = picture; + } + + if (request.BackgroundId is not null) + { + var background = await db.Files.Where(f => f.Id == request.BackgroundId).FirstOrDefaultAsync(); + if (background is null) return BadRequest("Invalid background id, unable to find the file on cloud."); + if (profile.Background is not null) + { + profile.Background.UsedCount--; + db.Update(profile.Background); + } + + background.UsedCount++; + profile.Background = background; + } + + await db.SaveChangesAsync(); + return profile; } } \ No newline at end of file diff --git a/DysonNetwork.Sphere/AppDatabase.cs b/DysonNetwork.Sphere/AppDatabase.cs index abbbc85..a4701ef 100644 --- a/DysonNetwork.Sphere/AppDatabase.cs +++ b/DysonNetwork.Sphere/AppDatabase.cs @@ -18,6 +18,7 @@ public class AppDatabase( ) : DbContext(options) { public DbSet Accounts { get; set; } + public DbSet AccountProfiles { get; set; } public DbSet AccountContacts { get; set; } public DbSet AccountAuthFactors { get; set; } public DbSet AuthSessions { get; set; } @@ -42,6 +43,11 @@ public class AppDatabase( protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); + + modelBuilder.Entity() + .HasOne(a => a.Profile) + .WithOne(p => p.Account) + .HasForeignKey(p => p.Id); // Automatically apply soft-delete filter to all entities inheriting BaseModel foreach (var entityType in modelBuilder.Model.GetEntityTypes()) diff --git a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj index 0faf296..2b01994 100644 --- a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj +++ b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj @@ -43,6 +43,7 @@ + diff --git a/DysonNetwork.Sphere/Migrations/20250408152422_InitialMigration.Designer.cs b/DysonNetwork.Sphere/Migrations/20250408152422_InitialMigration.Designer.cs deleted file mode 100644 index 6a2abc7..0000000 --- a/DysonNetwork.Sphere/Migrations/20250408152422_InitialMigration.Designer.cs +++ /dev/null @@ -1,190 +0,0 @@ -// -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250408152422_InitialMigration")] - partial class InitialMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.3") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.Account", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("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(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.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .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") - .HasColumnType("text") - .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("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .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.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.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Contacts"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250408152422_InitialMigration.cs b/DysonNetwork.Sphere/Migrations/20250408152422_InitialMigration.cs deleted file mode 100644 index 29fcad3..0000000 --- a/DysonNetwork.Sphere/Migrations/20250408152422_InitialMigration.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class InitialMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "accounts", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), - nick = table.Column(type: "character varying(256)", maxLength: 256, 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_accounts", x => x.id); - }); - - migrationBuilder.CreateTable( - name: "account_auth_factors", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - type = table.Column(type: "integer", nullable: false), - secret = table.Column(type: "text", nullable: true), - account_id = table.Column(type: "bigint", 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_account_auth_factors", x => x.id); - table.ForeignKey( - name: "fk_account_auth_factors_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "account_contacts", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - type = table.Column(type: "integer", nullable: false), - verified_at = table.Column(type: "timestamp with time zone", nullable: true), - content = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - account_id = table.Column(type: "bigint", 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_account_contacts", x => x.id); - table.ForeignKey( - name: "fk_account_contacts_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_account_auth_factors_account_id", - table: "account_auth_factors", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_account_contacts_account_id", - table: "account_contacts", - column: "account_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "account_auth_factors"); - - migrationBuilder.DropTable( - name: "account_contacts"); - - migrationBuilder.DropTable( - name: "accounts"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250410150812_AddAuthSession.Designer.cs b/DysonNetwork.Sphere/Migrations/20250410150812_AddAuthSession.Designer.cs deleted file mode 100644 index 2860f65..0000000 --- a/DysonNetwork.Sphere/Migrations/20250410150812_AddAuthSession.Designer.cs +++ /dev/null @@ -1,355 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250410150812_AddAuthSession")] - partial class AddAuthSession - { - /// - 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("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("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(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.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .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") - .HasColumnType("text") - .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("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .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.Auth.Challenge", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .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("IpAddress") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("ip_address"); - - b.Property("Nonce") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("nonce"); - - 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("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("bigint") - .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("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.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.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.Account.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Challenges"); - - b.Navigation("Contacts"); - - b.Navigation("Sessions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250410150812_AddAuthSession.cs b/DysonNetwork.Sphere/Migrations/20250410150812_AddAuthSession.cs deleted file mode 100644 index c7bba51..0000000 --- a/DysonNetwork.Sphere/Migrations/20250410150812_AddAuthSession.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddAuthSession : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "auth_challenges", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - step_remain = table.Column(type: "integer", nullable: false), - step_total = table.Column(type: "integer", nullable: false), - blacklist_factors = table.Column>(type: "jsonb", nullable: false), - audiences = table.Column>(type: "jsonb", nullable: false), - scopes = table.Column>(type: "jsonb", nullable: false), - ip_address = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), - user_agent = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), - device_id = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - nonce = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), - account_id = table.Column(type: "bigint", 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_auth_challenges", x => x.id); - table.ForeignKey( - name: "fk_auth_challenges_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "auth_sessions", - columns: table => new - { - id = table.Column(type: "uuid", nullable: false), - last_granted_at = table.Column(type: "timestamp with time zone", nullable: true), - expired_at = table.Column(type: "timestamp with time zone", nullable: true), - account_id = table.Column(type: "bigint", nullable: false), - challenge_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_auth_sessions", x => x.id); - table.ForeignKey( - name: "fk_auth_sessions_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "fk_auth_sessions_auth_challenges_challenge_id", - column: x => x.challenge_id, - principalTable: "auth_challenges", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_auth_challenges_account_id", - table: "auth_challenges", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_auth_sessions_account_id", - table: "auth_sessions", - column: "account_id"); - - migrationBuilder.CreateIndex( - name: "ix_auth_sessions_challenge_id", - table: "auth_sessions", - column: "challenge_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "auth_sessions"); - - migrationBuilder.DropTable( - name: "auth_challenges"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250410161354_AddSuperUser.Designer.cs b/DysonNetwork.Sphere/Migrations/20250410161354_AddSuperUser.Designer.cs deleted file mode 100644 index 44c0675..0000000 --- a/DysonNetwork.Sphere/Migrations/20250410161354_AddSuperUser.Designer.cs +++ /dev/null @@ -1,365 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Sphere; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250410161354_AddSuperUser")] - partial class AddSuperUser - { - /// - 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("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("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("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.ToTable("accounts", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Sphere.Account.AccountAuthFactor", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .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") - .HasColumnType("text") - .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("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountId") - .HasColumnType("bigint") - .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.Auth.Challenge", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("bigint") - .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("IpAddress") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("ip_address"); - - b.Property("Nonce") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("nonce"); - - 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("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("bigint") - .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("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.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.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.Account.Account", b => - { - b.Navigation("AuthFactors"); - - b.Navigation("Challenges"); - - b.Navigation("Contacts"); - - b.Navigation("Sessions"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250410161354_AddSuperUser.cs b/DysonNetwork.Sphere/Migrations/20250410161354_AddSuperUser.cs deleted file mode 100644 index 11db0f8..0000000 --- a/DysonNetwork.Sphere/Migrations/20250410161354_AddSuperUser.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddSuperUser : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "is_superuser", - table: "accounts", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "language", - table: "accounts", - type: "character varying(32)", - maxLength: 32, - nullable: false, - defaultValue: ""); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "is_superuser", - table: "accounts"); - - migrationBuilder.DropColumn( - name: "language", - table: "accounts"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250412182922_AddCloudFiles.cs b/DysonNetwork.Sphere/Migrations/20250412182922_AddCloudFiles.cs deleted file mode 100644 index c4664d4..0000000 --- a/DysonNetwork.Sphere/Migrations/20250412182922_AddCloudFiles.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; - -#nullable disable - -namespace DysonNetwork.Sphere.Migrations -{ - /// - public partial class AddCloudFiles : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "files", - columns: table => new - { - id = table.Column(type: "text", nullable: false), - name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), - description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), - file_meta = table.Column>(type: "jsonb", nullable: true), - user_meta = table.Column>(type: "jsonb", nullable: true), - mime_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - hash = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), - size = table.Column(type: "bigint", nullable: false), - uploaded_at = table.Column(type: "timestamp with time zone", nullable: true), - uploaded_to = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), - used_count = table.Column(type: "integer", nullable: false), - account_id = table.Column(type: "bigint", 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_files", x => x.id); - table.ForeignKey( - name: "fk_files_accounts_account_id", - column: x => x.account_id, - principalTable: "accounts", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "ix_files_account_id", - table: "files", - column: "account_id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "files"); - } - } -} diff --git a/DysonNetwork.Sphere/Migrations/20250412182922_AddCloudFiles.Designer.cs b/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.Designer.cs similarity index 83% rename from DysonNetwork.Sphere/Migrations/20250412182922_AddCloudFiles.Designer.cs rename to DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.Designer.cs index 1b94d9c..47979e0 100644 --- a/DysonNetwork.Sphere/Migrations/20250412182922_AddCloudFiles.Designer.cs +++ b/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.Designer.cs @@ -14,8 +14,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DysonNetwork.Sphere.Migrations { [DbContext(typeof(AppDatabase))] - [Migration("20250412182922_AddCloudFiles")] - partial class AddCloudFiles + [Migration("20250413115936_InitialMigration")] + partial class InitialMigration { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -166,6 +166,64 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("account_contacts", (string)null); }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => + { + b.Property("Id") + .HasColumnType("bigint") + .HasColumnName("id"); + + b.Property("BackgroundId") + .HasColumnType("text") + .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("text") + .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.Auth.Challenge", b => { b.Property("Id") @@ -393,6 +451,32 @@ namespace DysonNetwork.Sphere.Migrations 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.Auth.Challenge", b => { b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") @@ -446,6 +530,9 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Contacts"); + b.Navigation("Profile") + .IsRequired(); + b.Navigation("Sessions"); }); #pragma warning restore 612, 618 diff --git a/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.cs b/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.cs new file mode 100644 index 0000000..9c883e5 --- /dev/null +++ b/DysonNetwork.Sphere/Migrations/20250413115936_InitialMigration.cs @@ -0,0 +1,279 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DysonNetwork.Sphere.Migrations +{ + /// + public partial class InitialMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "accounts", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + nick = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + language = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), + is_superuser = table.Column(type: "boolean", 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_accounts", x => x.id); + }); + + migrationBuilder.CreateTable( + name: "account_auth_factors", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + type = table.Column(type: "integer", nullable: false), + secret = table.Column(type: "text", nullable: true), + account_id = table.Column(type: "bigint", 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_account_auth_factors", x => x.id); + table.ForeignKey( + name: "fk_account_auth_factors_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "account_contacts", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + type = table.Column(type: "integer", nullable: false), + verified_at = table.Column(type: "timestamp with time zone", nullable: true), + content = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + account_id = table.Column(type: "bigint", 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_account_contacts", x => x.id); + table.ForeignKey( + name: "fk_account_contacts_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "auth_challenges", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + step_remain = table.Column(type: "integer", nullable: false), + step_total = table.Column(type: "integer", nullable: false), + blacklist_factors = table.Column>(type: "jsonb", nullable: false), + audiences = table.Column>(type: "jsonb", nullable: false), + scopes = table.Column>(type: "jsonb", nullable: false), + ip_address = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + user_agent = table.Column(type: "character varying(512)", maxLength: 512, nullable: true), + device_id = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + nonce = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true), + account_id = table.Column(type: "bigint", 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_auth_challenges", x => x.id); + table.ForeignKey( + name: "fk_auth_challenges_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "files", + columns: table => new + { + id = table.Column(type: "text", nullable: false), + name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), + description = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + file_meta = table.Column>(type: "jsonb", nullable: true), + user_meta = table.Column>(type: "jsonb", nullable: true), + mime_type = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + hash = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + size = table.Column(type: "bigint", nullable: false), + uploaded_at = table.Column(type: "timestamp with time zone", nullable: true), + uploaded_to = table.Column(type: "character varying(128)", maxLength: 128, nullable: true), + used_count = table.Column(type: "integer", nullable: false), + account_id = table.Column(type: "bigint", 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_files", x => x.id); + table.ForeignKey( + name: "fk_files_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "auth_sessions", + columns: table => new + { + id = table.Column(type: "uuid", nullable: false), + last_granted_at = table.Column(type: "timestamp with time zone", nullable: true), + expired_at = table.Column(type: "timestamp with time zone", nullable: true), + account_id = table.Column(type: "bigint", nullable: false), + challenge_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_auth_sessions", x => x.id); + table.ForeignKey( + name: "fk_auth_sessions_accounts_account_id", + column: x => x.account_id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_auth_sessions_auth_challenges_challenge_id", + column: x => x.challenge_id, + principalTable: "auth_challenges", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "account_profiles", + columns: table => new + { + id = table.Column(type: "bigint", nullable: false), + first_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + middle_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + last_name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + bio = table.Column(type: "character varying(4096)", maxLength: 4096, nullable: true), + picture_id = table.Column(type: "text", nullable: true), + background_id = table.Column(type: "text", 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_account_profiles", x => x.id); + table.ForeignKey( + name: "fk_account_profiles_accounts_id", + column: x => x.id, + principalTable: "accounts", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_account_profiles_files_background_id", + column: x => x.background_id, + principalTable: "files", + principalColumn: "id"); + table.ForeignKey( + name: "fk_account_profiles_files_picture_id", + column: x => x.picture_id, + principalTable: "files", + principalColumn: "id"); + }); + + migrationBuilder.CreateIndex( + name: "ix_account_auth_factors_account_id", + table: "account_auth_factors", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_account_contacts_account_id", + table: "account_contacts", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_account_profiles_background_id", + table: "account_profiles", + column: "background_id"); + + migrationBuilder.CreateIndex( + name: "ix_account_profiles_picture_id", + table: "account_profiles", + column: "picture_id"); + + migrationBuilder.CreateIndex( + name: "ix_auth_challenges_account_id", + table: "auth_challenges", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_auth_sessions_account_id", + table: "auth_sessions", + column: "account_id"); + + migrationBuilder.CreateIndex( + name: "ix_auth_sessions_challenge_id", + table: "auth_sessions", + column: "challenge_id"); + + migrationBuilder.CreateIndex( + name: "ix_files_account_id", + table: "files", + column: "account_id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "account_auth_factors"); + + migrationBuilder.DropTable( + name: "account_contacts"); + + migrationBuilder.DropTable( + name: "account_profiles"); + + migrationBuilder.DropTable( + name: "auth_sessions"); + + migrationBuilder.DropTable( + name: "files"); + + migrationBuilder.DropTable( + name: "auth_challenges"); + + migrationBuilder.DropTable( + name: "accounts"); + } + } +} diff --git a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs index d5e35e9..664e2f0 100644 --- a/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Sphere/Migrations/AppDatabaseModelSnapshot.cs @@ -163,6 +163,64 @@ namespace DysonNetwork.Sphere.Migrations b.ToTable("account_contacts", (string)null); }); + modelBuilder.Entity("DysonNetwork.Sphere.Account.Profile", b => + { + b.Property("Id") + .HasColumnType("bigint") + .HasColumnName("id"); + + b.Property("BackgroundId") + .HasColumnType("text") + .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("text") + .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.Auth.Challenge", b => { b.Property("Id") @@ -390,6 +448,32 @@ namespace DysonNetwork.Sphere.Migrations 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.Auth.Challenge", b => { b.HasOne("DysonNetwork.Sphere.Account.Account", "Account") @@ -443,6 +527,9 @@ namespace DysonNetwork.Sphere.Migrations b.Navigation("Contacts"); + b.Navigation("Profile") + .IsRequired(); + b.Navigation("Sessions"); }); #pragma warning restore 612, 618