diff --git a/dotnet/AipsCore/Infrastructure/Persistence/Db/AipsDbContext.cs b/dotnet/AipsCore/Infrastructure/Persistence/Db/AipsDbContext.cs index 5aff8f0..ce13ff9 100644 --- a/dotnet/AipsCore/Infrastructure/Persistence/Db/AipsDbContext.cs +++ b/dotnet/AipsCore/Infrastructure/Persistence/Db/AipsDbContext.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Identity; +using AipsCore.Infrastructure.Persistence.Authentication.RefreshToken; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; @@ -6,6 +7,8 @@ namespace AipsCore.Infrastructure.Persistence.Db; public class AipsDbContext : IdentityDbContext, Guid> { + public DbSet RefreshTokens { get; set; } + public DbSet Whiteboards { get; set; } public DbSet Shapes { get; set; } public DbSet WhiteboardMemberships { get; set; } diff --git a/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/20260214171247_AddedRefreshTokens.Designer.cs b/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/20260214171247_AddedRefreshTokens.Designer.cs new file mode 100644 index 0000000..179c3a3 --- /dev/null +++ b/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/20260214171247_AddedRefreshTokens.Designer.cs @@ -0,0 +1,506 @@ +// +using System; +using AipsCore.Infrastructure.Persistence.Db; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace AipsCore.Infrastructure.Persistence.Db.Migrations +{ + [DbContext(typeof(AipsDbContext))] + [Migration("20260214171247_AddedRefreshTokens")] + partial class AddedRefreshTokens + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Authentication.RefreshToken.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Shape.Shape", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("Color") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("EndPositionX") + .HasColumnType("integer"); + + b.Property("EndPositionY") + .HasColumnType("integer"); + + b.Property("PositionX") + .HasColumnType("integer"); + + b.Property("PositionY") + .HasColumnType("integer"); + + b.Property("TextSize") + .HasColumnType("integer"); + + b.Property("TextValue") + .HasColumnType("text"); + + b.Property("Thickness") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("WhiteboardId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("WhiteboardId"); + + b.ToTable("Shapes"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.User.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Whiteboard.Whiteboard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("JoinPolicy") + .HasColumnType("integer"); + + b.Property("MaxParticipants") + .HasColumnType("integer"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Whiteboards"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.WhiteboardMembership.WhiteboardMembership", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CanJoin") + .HasColumnType("boolean"); + + b.Property("EditingEnabled") + .HasColumnType("boolean"); + + b.Property("IsBanned") + .HasColumnType("boolean"); + + b.Property("LastInteractedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("WhiteboardId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("WhiteboardId"); + + b.ToTable("WhiteboardMemberships"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Authentication.RefreshToken.RefreshToken", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Shape.Shape", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", "Author") + .WithMany("Shapes") + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AipsCore.Infrastructure.Persistence.Whiteboard.Whiteboard", "Whiteboard") + .WithMany("Shapes") + .HasForeignKey("WhiteboardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + + b.Navigation("Whiteboard"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Whiteboard.Whiteboard", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", "Owner") + .WithMany("Whiteboards") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.WhiteboardMembership.WhiteboardMembership", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", "User") + .WithMany("Memberships") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AipsCore.Infrastructure.Persistence.Whiteboard.Whiteboard", "Whiteboard") + .WithMany("Memberships") + .HasForeignKey("WhiteboardId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + + b.Navigation("Whiteboard"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.User.User", b => + { + b.Navigation("Memberships"); + + b.Navigation("Shapes"); + + b.Navigation("Whiteboards"); + }); + + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Whiteboard.Whiteboard", b => + { + b.Navigation("Memberships"); + + b.Navigation("Shapes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/20260214171247_AddedRefreshTokens.cs b/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/20260214171247_AddedRefreshTokens.cs new file mode 100644 index 0000000..11fde22 --- /dev/null +++ b/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/20260214171247_AddedRefreshTokens.cs @@ -0,0 +1,47 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AipsCore.Infrastructure.Persistence.Db.Migrations +{ + /// + public partial class AddedRefreshTokens : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "RefreshTokens", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Token = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + ExpiresAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RefreshTokens", x => x.Id); + table.ForeignKey( + name: "FK_RefreshTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RefreshTokens_UserId", + table: "RefreshTokens", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RefreshTokens"); + } + } +} diff --git a/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/AipsDbContextModelSnapshot.cs b/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/AipsDbContextModelSnapshot.cs index a0c1825..fe16030 100644 --- a/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/AipsDbContextModelSnapshot.cs +++ b/dotnet/AipsCore/Infrastructure/Persistence/Db/Migrations/AipsDbContextModelSnapshot.cs @@ -22,6 +22,30 @@ namespace AipsCore.Infrastructure.Persistence.Db.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Authentication.RefreshToken.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Shape.Shape", b => { b.Property("Id") @@ -347,6 +371,17 @@ namespace AipsCore.Infrastructure.Persistence.Db.Migrations b.ToTable("AspNetUserTokens", (string)null); }); + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Authentication.RefreshToken.RefreshToken", b => + { + b.HasOne("AipsCore.Infrastructure.Persistence.User.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + modelBuilder.Entity("AipsCore.Infrastructure.Persistence.Shape.Shape", b => { b.HasOne("AipsCore.Infrastructure.Persistence.User.User", "Author")