From b97c2038a620e30e54012a81f5eb5c4f025dc7b7 Mon Sep 17 00:00:00 2001 From: movingsam Date: Sat, 21 Feb 2026 15:05:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RoleAggregate/ApplicationRole.cs | 2 +- .../TenantAggregate/TenantInfo.cs | 15 +- .../UserAggregate/ApplicationUser.cs | 11 +- .../ITenantStore.cs | 2 +- .../20260218145512_Initial.Designer.cs | 95 --- .../Migrations/20260218145512_Initial.cs | 57 -- .../20260221065049_Initial.Designer.cs | 565 ++++++++++++++++++ .../Migrations/20260221065049_Initial.cs | 391 ++++++++++++ .../PlatformDbContextModelSnapshot.cs | 482 ++++++++++++++- .../Migrations/sql/20260221065049_initial.sql | 191 ++++++ .../PlatformDbContext.cs | 5 +- Fengling.Platform.Infrastructure/SeedData.cs | 51 +- .../TenantManager.cs | 4 +- .../TenantStore.cs | 3 +- 14 files changed, 1694 insertions(+), 180 deletions(-) delete mode 100644 Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.Designer.cs delete mode 100644 Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.cs create mode 100644 Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.Designer.cs create mode 100644 Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.cs create mode 100644 Fengling.Platform.Infrastructure/Migrations/sql/20260221065049_initial.sql diff --git a/Fengling.Platform.Domain/AggregatesModel/RoleAggregate/ApplicationRole.cs b/Fengling.Platform.Domain/AggregatesModel/RoleAggregate/ApplicationRole.cs index 3f6b863..9116b8c 100644 --- a/Fengling.Platform.Domain/AggregatesModel/RoleAggregate/ApplicationRole.cs +++ b/Fengling.Platform.Domain/AggregatesModel/RoleAggregate/ApplicationRole.cs @@ -5,7 +5,7 @@ namespace Fengling.Platform.Domain.AggregatesModel.RoleAggregate; public class ApplicationRole : IdentityRole { public string? Description { get; set; } - public DateTime CreatedTime { get; set; } = DateTime.UtcNow; + public DateTimeOffset CreatedTime { get; set; } = DateTimeOffset.UtcNow; public long? TenantId { get; set; } public bool IsSystem { get; set; } public string? DisplayName { get; set; } diff --git a/Fengling.Platform.Domain/AggregatesModel/TenantAggregate/TenantInfo.cs b/Fengling.Platform.Domain/AggregatesModel/TenantAggregate/TenantInfo.cs index 76d53e3..b0f319b 100644 --- a/Fengling.Platform.Domain/AggregatesModel/TenantAggregate/TenantInfo.cs +++ b/Fengling.Platform.Domain/AggregatesModel/TenantAggregate/TenantInfo.cs @@ -1,19 +1,24 @@ namespace Fengling.Platform.Domain.AggregatesModel.TenantAggregate; /// -/// +/// 租户信息 /// /// /// /// -public record TenantInfo(long TenantId, string TenantCode, string TenantName) +public record TenantInfo(long? TenantId, string? TenantCode, string? TenantName) { /// - /// + /// 租户信息 /// /// - public TenantInfo(Tenant tenant) - : this(tenant.Id, tenant.TenantCode, tenant.Name) + public TenantInfo(Tenant? tenant) + : this(tenant?.Id, tenant?.TenantCode, tenant?.Name) { } + + /// + /// 无租户,系统级 + /// + public static TenantInfo Admin => new TenantInfo(null, null, null); } \ No newline at end of file diff --git a/Fengling.Platform.Domain/AggregatesModel/UserAggregate/ApplicationUser.cs b/Fengling.Platform.Domain/AggregatesModel/UserAggregate/ApplicationUser.cs index 69df260..36de46e 100644 --- a/Fengling.Platform.Domain/AggregatesModel/UserAggregate/ApplicationUser.cs +++ b/Fengling.Platform.Domain/AggregatesModel/UserAggregate/ApplicationUser.cs @@ -5,10 +5,9 @@ namespace Fengling.Platform.Domain.AggregatesModel.UserAggregate; public class ApplicationUser : IdentityUser { - public string? RealName { get; set; } - public string? Phone { get; set; } - public TenantInfo TenantInfo { get; set; } = null!; - public DateTime CreatedTime { get; set; } = DateTime.UtcNow; - public DateTime? UpdatedTime { get; set; } + public string RealName { get; set; } + public TenantInfo? TenantInfo { get; set; } + public DateTimeOffset CreatedTime { get; set; } = DateTimeOffset.UtcNow; + public DateTimeOffset? UpdatedTime { get; set; } public bool IsDeleted { get; set; } -} +} \ No newline at end of file diff --git a/Fengling.Platform.Infrastructure/ITenantStore.cs b/Fengling.Platform.Infrastructure/ITenantStore.cs index be69c8c..fee92dd 100644 --- a/Fengling.Platform.Infrastructure/ITenantStore.cs +++ b/Fengling.Platform.Infrastructure/ITenantStore.cs @@ -4,7 +4,7 @@ using Fengling.Platform.Domain.AggregatesModel.TenantAggregate; public interface ITenantStore { - Task FindByIdAsync(long tenantId, CancellationToken cancellationToken = default); + Task FindByIdAsync(long? tenantId, CancellationToken cancellationToken = default); Task FindByTenantCodeAsync(string tenantCode, CancellationToken cancellationToken = default); Task> GetAllAsync(CancellationToken cancellationToken = default); Task> GetPagedAsync(int page, int pageSize, string? name = null, string? tenantCode = null, TenantStatus? status = null, CancellationToken cancellationToken = default); diff --git a/Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.Designer.cs b/Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.Designer.cs deleted file mode 100644 index 98808de..0000000 --- a/Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.Designer.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -using System; -using Fengling.Platform.Infrastructure; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Fengling.Platform.Infrastructure.Migrations -{ - [DbContext(typeof(PlatformDbContext))] - [Migration("20260218145512_Initial")] - partial class Initial - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.0") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.Tenant", b => - { - b.Property("Id") - .HasColumnType("bigint"); - - b.Property("ContactEmail") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ContactName") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("ContactPhone") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Deleted") - .HasColumnType("boolean"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MaxUsers") - .HasColumnType("integer"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("integer"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("TenantCode") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("Status"); - - b.HasIndex("TenantCode") - .IsUnique(); - - b.ToTable("Platform_Tenants", (string)null); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.cs b/Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.cs deleted file mode 100644 index 5cde810..0000000 --- a/Fengling.Platform.Infrastructure/Migrations/20260218145512_Initial.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Fengling.Platform.Infrastructure.Migrations -{ - /// - public partial class Initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Platform_Tenants", - columns: table => new - { - Id = table.Column(type: "bigint", nullable: false), - TenantCode = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), - Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - ContactName = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), - ContactEmail = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - ContactPhone = table.Column(type: "character varying(20)", maxLength: 20, nullable: true), - MaxUsers = table.Column(type: "integer", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true), - ExpiresAt = table.Column(type: "timestamp with time zone", nullable: true), - Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), - Status = table.Column(type: "integer", nullable: false), - Deleted = table.Column(type: "boolean", nullable: false), - RowVersion = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Platform_Tenants", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_Platform_Tenants_Status", - table: "Platform_Tenants", - column: "Status"); - - migrationBuilder.CreateIndex( - name: "IX_Platform_Tenants_TenantCode", - table: "Platform_Tenants", - column: "TenantCode", - unique: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Platform_Tenants"); - } - } -} diff --git a/Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.Designer.cs b/Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.Designer.cs new file mode 100644 index 0000000..d2e5722 --- /dev/null +++ b/Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.Designer.cs @@ -0,0 +1,565 @@ +// +using System; +using System.Collections.Generic; +using Fengling.Platform.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Fengling.Platform.Infrastructure.Migrations +{ + [DbContext(typeof(PlatformDbContext))] + [Migration("20260221065049_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("IsSystem") + .HasColumnType("boolean"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.PrimitiveCollection>("Permissions") + .HasColumnType("text[]"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ContactEmail") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ContactName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ContactPhone") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("MaxUsers") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("RowVersion") + .HasColumnType("bigint"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantCode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Status"); + + b.HasIndex("TenantCode") + .IsUnique(); + + b.ToTable("Platform_Tenants", (string)null); + }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AccessLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("integer"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Method") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("RequestData") + .HasColumnType("text"); + + b.Property("Resource") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ResponseData") + .HasColumnType("text"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TenantId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("UserName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("Status"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserName"); + + b.ToTable("AccessLogs"); + }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .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") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("RealName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UpdatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NewValue") + .HasColumnType("text"); + + b.Property("OldValue") + .HasColumnType("text"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Operator") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TargetId") + .HasColumnType("bigint"); + + b.Property("TargetName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TargetType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("Operation"); + + b.HasIndex("Operator"); + + b.HasIndex("TenantId"); + + b.ToTable("AuditLogs"); + }); + + 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("bigint"); + + 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("bigint"); + + 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("bigint"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("bigint"); + + 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("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b => + { + b.OwnsOne("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.TenantInfo", "TenantInfo", b1 => + { + b1.Property("ApplicationUserId") + .HasColumnType("bigint"); + + b1.Property("TenantCode") + .HasColumnType("text") + .HasColumnName("TenantCode"); + + b1.Property("TenantId") + .HasColumnType("bigint") + .HasColumnName("TenantId"); + + b1.Property("TenantName") + .HasColumnType("text") + .HasColumnName("TenantName"); + + b1.HasKey("ApplicationUserId"); + + b1.ToTable("AspNetUsers"); + + b1.WithOwner() + .HasForeignKey("ApplicationUserId"); + }); + + b.Navigation("TenantInfo"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.cs b/Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.cs new file mode 100644 index 0000000..e4373cc --- /dev/null +++ b/Fengling.Platform.Infrastructure/Migrations/20260221065049_Initial.cs @@ -0,0 +1,391 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Fengling.Platform.Infrastructure.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AccessLogs", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserName = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Resource = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + Method = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), + IpAddress = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + UserAgent = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Duration = table.Column(type: "integer", nullable: false), + RequestData = table.Column(type: "text", nullable: true), + ResponseData = table.Column(type: "text", nullable: true), + ErrorMessage = table.Column(type: "text", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccessLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Description = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + CreatedTime = table.Column(type: "timestamp with time zone", nullable: false), + TenantId = table.Column(type: "bigint", nullable: true), + IsSystem = table.Column(type: "boolean", nullable: false), + DisplayName = table.Column(type: "text", nullable: true), + Permissions = table.Column>(type: "text[]", nullable: true), + Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + RealName = table.Column(type: "text", nullable: false), + TenantId = table.Column(type: "bigint", nullable: true), + TenantCode = table.Column(type: "text", nullable: true), + TenantName = table.Column(type: "text", nullable: true), + CreatedTime = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedTime = table.Column(type: "timestamp with time zone", nullable: true), + IsDeleted = table.Column(type: "boolean", nullable: false), + UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "boolean", nullable: false), + PasswordHash = table.Column(type: "text", nullable: true), + SecurityStamp = table.Column(type: "text", nullable: true), + ConcurrencyStamp = table.Column(type: "text", nullable: true), + PhoneNumber = table.Column(type: "character varying(20)", maxLength: 20, nullable: true), + PhoneNumberConfirmed = table.Column(type: "boolean", nullable: false), + TwoFactorEnabled = table.Column(type: "boolean", nullable: false), + LockoutEnd = table.Column(type: "timestamp with time zone", nullable: true), + LockoutEnabled = table.Column(type: "boolean", nullable: false), + AccessFailedCount = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AuditLogs", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Operator = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + Operation = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + TargetType = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + TargetId = table.Column(type: "bigint", nullable: true), + TargetName = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + IpAddress = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + OldValue = table.Column(type: "text", nullable: true), + NewValue = table.Column(type: "text", nullable: true), + ErrorMessage = table.Column(type: "text", nullable: true), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Platform_Tenants", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + TenantCode = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + ContactName = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + ContactEmail = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + ContactPhone = table.Column(type: "character varying(20)", maxLength: 20, nullable: true), + MaxUsers = table.Column(type: "integer", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true), + ExpiresAt = table.Column(type: "timestamp with time zone", nullable: true), + Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + Status = table.Column(type: "integer", nullable: false), + IsDeleted = table.Column(type: "boolean", nullable: false), + RowVersion = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Platform_Tenants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + RoleId = table.Column(type: "bigint", nullable: false), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "bigint", nullable: false), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "text", nullable: false), + ProviderKey = table.Column(type: "text", nullable: false), + ProviderDisplayName = table.Column(type: "text", nullable: true), + UserId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "bigint", nullable: false), + RoleId = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "bigint", nullable: false), + LoginProvider = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Value = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_Action", + table: "AccessLogs", + column: "Action"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_CreatedAt", + table: "AccessLogs", + column: "CreatedAt"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_Status", + table: "AccessLogs", + column: "Status"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_TenantId", + table: "AccessLogs", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_UserName", + table: "AccessLogs", + column: "UserName"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_PhoneNumber", + table: "AspNetUsers", + column: "PhoneNumber", + unique: true); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Action", + table: "AuditLogs", + column: "Action"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_CreatedAt", + table: "AuditLogs", + column: "CreatedAt"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Operation", + table: "AuditLogs", + column: "Operation"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Operator", + table: "AuditLogs", + column: "Operator"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_TenantId", + table: "AuditLogs", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_Platform_Tenants_Status", + table: "Platform_Tenants", + column: "Status"); + + migrationBuilder.CreateIndex( + name: "IX_Platform_Tenants_TenantCode", + table: "Platform_Tenants", + column: "TenantCode", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccessLogs"); + + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "AuditLogs"); + + migrationBuilder.DropTable( + name: "Platform_Tenants"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs b/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs index 5c017f2..d2764de 100644 --- a/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs +++ b/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs @@ -1,5 +1,6 @@ // using System; +using System.Collections.Generic; using Fengling.Platform.Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -22,11 +23,62 @@ namespace Fengling.Platform.Infrastructure.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("IsSystem") + .HasColumnType("boolean"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.PrimitiveCollection>("Permissions") + .HasColumnType("text[]"); + + b.Property("TenantId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.Tenant", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("bigint"); + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("ContactEmail") .IsRequired() .HasMaxLength(100) @@ -44,9 +96,6 @@ namespace Fengling.Platform.Infrastructure.Migrations b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); - b.Property("Deleted") - .HasColumnType("boolean"); - b.Property("Description") .HasMaxLength(500) .HasColumnType("character varying(500)"); @@ -54,6 +103,9 @@ namespace Fengling.Platform.Infrastructure.Migrations b.Property("ExpiresAt") .HasColumnType("timestamp with time zone"); + b.Property("IsDeleted") + .HasColumnType("boolean"); + b.Property("MaxUsers") .HasColumnType("integer"); @@ -62,9 +114,8 @@ namespace Fengling.Platform.Infrastructure.Migrations .HasMaxLength(100) .HasColumnType("character varying(100)"); - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("integer"); + b.Property("RowVersion") + .HasColumnType("bigint"); b.Property("Status") .HasColumnType("integer"); @@ -86,6 +137,425 @@ namespace Fengling.Platform.Infrastructure.Migrations b.ToTable("Platform_Tenants", (string)null); }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AccessLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .HasColumnType("integer"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Method") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("RequestData") + .HasColumnType("text"); + + b.Property("Resource") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ResponseData") + .HasColumnType("text"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TenantId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("UserName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("Status"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserName"); + + b.ToTable("AccessLogs"); + }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .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") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("RealName") + .IsRequired() + .HasColumnType("text"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UpdatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("PhoneNumber") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NewValue") + .HasColumnType("text"); + + b.Property("OldValue") + .HasColumnType("text"); + + b.Property("Operation") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Operator") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TargetId") + .HasColumnType("bigint"); + + b.Property("TargetName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TargetType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("Operation"); + + b.HasIndex("Operator"); + + b.HasIndex("TenantId"); + + b.ToTable("AuditLogs"); + }); + + 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("bigint"); + + 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("bigint"); + + 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("bigint"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("RoleId") + .HasColumnType("bigint"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("bigint"); + + 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("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b => + { + b.OwnsOne("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.TenantInfo", "TenantInfo", b1 => + { + b1.Property("ApplicationUserId") + .HasColumnType("bigint"); + + b1.Property("TenantCode") + .HasColumnType("text") + .HasColumnName("TenantCode"); + + b1.Property("TenantId") + .HasColumnType("bigint") + .HasColumnName("TenantId"); + + b1.Property("TenantName") + .HasColumnType("text") + .HasColumnName("TenantName"); + + b1.HasKey("ApplicationUserId"); + + b1.ToTable("AspNetUsers"); + + b1.WithOwner() + .HasForeignKey("ApplicationUserId"); + }); + + b.Navigation("TenantInfo"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); #pragma warning restore 612, 618 } } diff --git a/Fengling.Platform.Infrastructure/Migrations/sql/20260221065049_initial.sql b/Fengling.Platform.Infrastructure/Migrations/sql/20260221065049_initial.sql new file mode 100644 index 0000000..bf4b12a --- /dev/null +++ b/Fengling.Platform.Infrastructure/Migrations/sql/20260221065049_initial.sql @@ -0,0 +1,191 @@ +CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" ( + "MigrationId" character varying(150) NOT NULL, + "ProductVersion" character varying(32) NOT NULL, + CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId") +); + +START TRANSACTION; +CREATE TABLE "AccessLogs" ( + "Id" bigint GENERATED BY DEFAULT AS IDENTITY, + "UserName" character varying(50), + "TenantId" character varying(50), + "Action" character varying(20) NOT NULL, + "Resource" character varying(200), + "Method" character varying(10), + "IpAddress" character varying(50), + "UserAgent" character varying(500), + "Status" character varying(20) NOT NULL, + "Duration" integer NOT NULL, + "RequestData" text, + "ResponseData" text, + "ErrorMessage" text, + "CreatedAt" timestamp with time zone NOT NULL, + CONSTRAINT "PK_AccessLogs" PRIMARY KEY ("Id") +); + +CREATE TABLE "AspNetRoles" ( + "Id" bigint GENERATED BY DEFAULT AS IDENTITY, + "Description" character varying(200), + "CreatedTime" timestamp with time zone NOT NULL, + "TenantId" bigint, + "IsSystem" boolean NOT NULL, + "DisplayName" text, + "Permissions" text[], + "Name" character varying(256), + "NormalizedName" character varying(256), + "ConcurrencyStamp" text, + CONSTRAINT "PK_AspNetRoles" PRIMARY KEY ("Id") +); + +CREATE TABLE "AspNetUsers" ( + "Id" bigint GENERATED BY DEFAULT AS IDENTITY, + "RealName" text NOT NULL, + "TenantId" bigint, + "TenantCode" text, + "TenantName" text, + "CreatedTime" timestamp with time zone NOT NULL, + "UpdatedTime" timestamp with time zone, + "IsDeleted" boolean NOT NULL, + "UserName" character varying(256), + "NormalizedUserName" character varying(256), + "Email" character varying(256), + "NormalizedEmail" character varying(256), + "EmailConfirmed" boolean NOT NULL, + "PasswordHash" text, + "SecurityStamp" text, + "ConcurrencyStamp" text, + "PhoneNumber" character varying(20), + "PhoneNumberConfirmed" boolean NOT NULL, + "TwoFactorEnabled" boolean NOT NULL, + "LockoutEnd" timestamp with time zone, + "LockoutEnabled" boolean NOT NULL, + "AccessFailedCount" integer NOT NULL, + CONSTRAINT "PK_AspNetUsers" PRIMARY KEY ("Id") +); + +CREATE TABLE "AuditLogs" ( + "Id" bigint GENERATED BY DEFAULT AS IDENTITY, + "Operator" character varying(50) NOT NULL, + "TenantId" character varying(50), + "Operation" character varying(20) NOT NULL, + "Action" character varying(20) NOT NULL, + "TargetType" character varying(50), + "TargetId" bigint, + "TargetName" character varying(100), + "IpAddress" character varying(50) NOT NULL, + "Description" character varying(500), + "OldValue" text, + "NewValue" text, + "ErrorMessage" text, + "Status" character varying(20) NOT NULL, + "CreatedAt" timestamp with time zone NOT NULL, + CONSTRAINT "PK_AuditLogs" PRIMARY KEY ("Id") +); + +CREATE TABLE "Platform_Tenants" ( + "Id" bigint GENERATED BY DEFAULT AS IDENTITY, + "TenantCode" character varying(50) NOT NULL, + "Name" character varying(100) NOT NULL, + "ContactName" character varying(50) NOT NULL, + "ContactEmail" character varying(100) NOT NULL, + "ContactPhone" character varying(20), + "MaxUsers" integer, + "CreatedAt" timestamp with time zone NOT NULL, + "UpdatedAt" timestamp with time zone, + "ExpiresAt" timestamp with time zone, + "Description" character varying(500), + "Status" integer NOT NULL, + "IsDeleted" boolean NOT NULL, + "RowVersion" bigint NOT NULL, + CONSTRAINT "PK_Platform_Tenants" PRIMARY KEY ("Id") +); + +CREATE TABLE "AspNetRoleClaims" ( + "Id" integer GENERATED BY DEFAULT AS IDENTITY, + "RoleId" bigint NOT NULL, + "ClaimType" text, + "ClaimValue" text, + CONSTRAINT "PK_AspNetRoleClaims" PRIMARY KEY ("Id"), + CONSTRAINT "FK_AspNetRoleClaims_AspNetRoles_RoleId" FOREIGN KEY ("RoleId") REFERENCES "AspNetRoles" ("Id") ON DELETE CASCADE +); + +CREATE TABLE "AspNetUserClaims" ( + "Id" integer GENERATED BY DEFAULT AS IDENTITY, + "UserId" bigint NOT NULL, + "ClaimType" text, + "ClaimValue" text, + CONSTRAINT "PK_AspNetUserClaims" PRIMARY KEY ("Id"), + CONSTRAINT "FK_AspNetUserClaims_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES "AspNetUsers" ("Id") ON DELETE CASCADE +); + +CREATE TABLE "AspNetUserLogins" ( + "LoginProvider" text NOT NULL, + "ProviderKey" text NOT NULL, + "ProviderDisplayName" text, + "UserId" bigint NOT NULL, + CONSTRAINT "PK_AspNetUserLogins" PRIMARY KEY ("LoginProvider", "ProviderKey"), + CONSTRAINT "FK_AspNetUserLogins_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES "AspNetUsers" ("Id") ON DELETE CASCADE +); + +CREATE TABLE "AspNetUserRoles" ( + "UserId" bigint NOT NULL, + "RoleId" bigint NOT NULL, + CONSTRAINT "PK_AspNetUserRoles" PRIMARY KEY ("UserId", "RoleId"), + CONSTRAINT "FK_AspNetUserRoles_AspNetRoles_RoleId" FOREIGN KEY ("RoleId") REFERENCES "AspNetRoles" ("Id") ON DELETE CASCADE, + CONSTRAINT "FK_AspNetUserRoles_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES "AspNetUsers" ("Id") ON DELETE CASCADE +); + +CREATE TABLE "AspNetUserTokens" ( + "UserId" bigint NOT NULL, + "LoginProvider" text NOT NULL, + "Name" text NOT NULL, + "Value" text, + CONSTRAINT "PK_AspNetUserTokens" PRIMARY KEY ("UserId", "LoginProvider", "Name"), + CONSTRAINT "FK_AspNetUserTokens_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES "AspNetUsers" ("Id") ON DELETE CASCADE +); + +CREATE INDEX "IX_AccessLogs_Action" ON "AccessLogs" ("Action"); + +CREATE INDEX "IX_AccessLogs_CreatedAt" ON "AccessLogs" ("CreatedAt"); + +CREATE INDEX "IX_AccessLogs_Status" ON "AccessLogs" ("Status"); + +CREATE INDEX "IX_AccessLogs_TenantId" ON "AccessLogs" ("TenantId"); + +CREATE INDEX "IX_AccessLogs_UserName" ON "AccessLogs" ("UserName"); + +CREATE INDEX "IX_AspNetRoleClaims_RoleId" ON "AspNetRoleClaims" ("RoleId"); + +CREATE UNIQUE INDEX "RoleNameIndex" ON "AspNetRoles" ("NormalizedName"); + +CREATE INDEX "IX_AspNetUserClaims_UserId" ON "AspNetUserClaims" ("UserId"); + +CREATE INDEX "IX_AspNetUserLogins_UserId" ON "AspNetUserLogins" ("UserId"); + +CREATE INDEX "IX_AspNetUserRoles_RoleId" ON "AspNetUserRoles" ("RoleId"); + +CREATE INDEX "EmailIndex" ON "AspNetUsers" ("NormalizedEmail"); + +CREATE UNIQUE INDEX "IX_AspNetUsers_PhoneNumber" ON "AspNetUsers" ("PhoneNumber"); + +CREATE UNIQUE INDEX "UserNameIndex" ON "AspNetUsers" ("NormalizedUserName"); + +CREATE INDEX "IX_AuditLogs_Action" ON "AuditLogs" ("Action"); + +CREATE INDEX "IX_AuditLogs_CreatedAt" ON "AuditLogs" ("CreatedAt"); + +CREATE INDEX "IX_AuditLogs_Operation" ON "AuditLogs" ("Operation"); + +CREATE INDEX "IX_AuditLogs_Operator" ON "AuditLogs" ("Operator"); + +CREATE INDEX "IX_AuditLogs_TenantId" ON "AuditLogs" ("TenantId"); + +CREATE INDEX "IX_Platform_Tenants_Status" ON "Platform_Tenants" ("Status"); + +CREATE UNIQUE INDEX "IX_Platform_Tenants_TenantCode" ON "Platform_Tenants" ("TenantCode"); + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20260221065049_Initial', '10.0.0'); + +COMMIT; + diff --git a/Fengling.Platform.Infrastructure/PlatformDbContext.cs b/Fengling.Platform.Infrastructure/PlatformDbContext.cs index 1126512..91f702d 100644 --- a/Fengling.Platform.Infrastructure/PlatformDbContext.cs +++ b/Fengling.Platform.Infrastructure/PlatformDbContext.cs @@ -24,9 +24,8 @@ public partial class PlatformDbContext(DbContextOptions optio modelBuilder.Entity(entity => { - entity.Property(e => e.RealName).HasMaxLength(100); - entity.Property(e => e.Phone).HasMaxLength(20); - entity.HasIndex(e => e.Phone).IsUnique(); + entity.Property(e => e.PhoneNumber).HasMaxLength(20); + entity.HasIndex(e => e.PhoneNumber).IsUnique(); entity.OwnsOne(e => e.TenantInfo, navigationBuilder => { diff --git a/Fengling.Platform.Infrastructure/SeedData.cs b/Fengling.Platform.Infrastructure/SeedData.cs index daa30c7..629c68c 100644 --- a/Fengling.Platform.Infrastructure/SeedData.cs +++ b/Fengling.Platform.Infrastructure/SeedData.cs @@ -1,15 +1,24 @@ +using Fengling.Platform.Domain.AggregatesModel.RoleAggregate; using Fengling.Platform.Domain.AggregatesModel.TenantAggregate; +using Fengling.Platform.Domain.AggregatesModel.UserAggregate; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; namespace Fengling.Platform.Infrastructure; public static class SeedData { - public static async Task InitializeAsync(this PlatformDbContext context) + + public static async Task InitializeAsync(this IServiceScope scope) { + var userManager = scope.ServiceProvider.GetRequiredService>(); + var roleManager = scope.ServiceProvider.GetRequiredService>(); + + var context= scope.ServiceProvider.GetRequiredService(); await context.Database.EnsureCreatedAsync(); var adminTenant = context.Tenants - .FirstOrDefault(t => t.Name == "Administrator"); + .FirstOrDefault(t => t.TenantCode == "Administrator"); if (adminTenant != null) { return adminTenant; @@ -17,7 +26,7 @@ public static class SeedData adminTenant = new Tenant { - TenantCode = "admin", + TenantCode = "Administrator", Name = "超级系统", ContactName = "", ContactEmail = "", @@ -25,6 +34,42 @@ public static class SeedData CreatedAt = DateTime.UtcNow }; await context.Tenants.AddAsync(adminTenant); + + + var role = await roleManager.Roles + .OfType() + .AsQueryable() + .FirstOrDefaultAsync(x=>x.Name == "admin" && x.TenantId ==null); + + if (role == null) + { + role = new ApplicationRole() + { + CreatedTime = DateTimeOffset.UtcNow, + TenantId = null, + Name = "admin", Description = "系统管理员", + DisplayName = "系统管理员", + IsSystem = true, + }; + await roleManager.CreateAsync(role); + } + + var user = await userManager.FindByNameAsync("admin"); + if (user != null) + { + user = new ApplicationUser() + { + UserName = "admin", + RealName = "系统超级管理员", + Email = "samsu9194@163.com", + TenantInfo = new TenantInfo(adminTenant), + PhoneNumber = "15921072307" + }; + await userManager.AddToRoleAsync(user, "admin"); + await userManager.CreateAsync(user, "admin"); + } + + await context.SaveChangesAsync(); return adminTenant; } diff --git a/Fengling.Platform.Infrastructure/TenantManager.cs b/Fengling.Platform.Infrastructure/TenantManager.cs index 13ee0c6..f338b1e 100644 --- a/Fengling.Platform.Infrastructure/TenantManager.cs +++ b/Fengling.Platform.Infrastructure/TenantManager.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Identity; public interface ITenantManager { - Task FindByIdAsync(long tenantId, CancellationToken cancellationToken = default); + Task FindByIdAsync(long? tenantId, CancellationToken cancellationToken = default); Task FindByTenantCodeAsync(string tenantCode, CancellationToken cancellationToken = default); Task> GetAllAsync(CancellationToken cancellationToken = default); Task> GetPagedAsync(int page, int pageSize, string? name = null, string? tenantCode = null, TenantStatus? status = null, CancellationToken cancellationToken = default); @@ -19,7 +19,7 @@ public interface ITenantManager public sealed class TenantManager(ITenantStore store) : ITenantManager { - public async Task FindByIdAsync(long tenantId, CancellationToken cancellationToken = default) + public async Task FindByIdAsync(long? tenantId, CancellationToken cancellationToken = default) { return await store.FindByIdAsync(tenantId, cancellationToken); } diff --git a/Fengling.Platform.Infrastructure/TenantStore.cs b/Fengling.Platform.Infrastructure/TenantStore.cs index 4c4b979..c358929 100644 --- a/Fengling.Platform.Infrastructure/TenantStore.cs +++ b/Fengling.Platform.Infrastructure/TenantStore.cs @@ -17,8 +17,9 @@ public class TenantStore : ITenantStore public void Dispose() { } - public virtual Task FindByIdAsync(long tenantId, CancellationToken cancellationToken = default) + public virtual Task FindByIdAsync(long? tenantId, CancellationToken cancellationToken = default) { + if (tenantId == null) return Task.FromResult(null); return _tenants.FirstOrDefaultAsync(t => t.Id == tenantId, cancellationToken); }