277 lines
11 KiB
C#
277 lines
11 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
using Microsoft.EntityFrameworkCore.ValueGeneration;
|
|
using Modules.User.Database.Database.Entities;
|
|
|
|
namespace Modules.User.Database.Database;
|
|
|
|
public class UserDbContext : DbContext
|
|
{
|
|
public DbSet<Account> Accounts { get; set; }
|
|
public DbSet<Entities.User> Users { get; set; }
|
|
public DbSet<Session> Sessions { get; set; }
|
|
|
|
public DbSet<Role> Roles { get; set; }
|
|
public DbSet<AccountRole> AccountRoles { get; set; }
|
|
|
|
public DbSet<Permission> Permissions { get; set; }
|
|
public DbSet<AccountPermission> AccountPermissions { get; set; }
|
|
|
|
public UserDbContext(DbContextOptions<UserDbContext> options) : base(options)
|
|
{
|
|
|
|
}
|
|
|
|
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
|
|
{
|
|
configurationBuilder.Properties<Enum>().HaveConversion<string>();
|
|
}
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
modelBuilder.Entity<Entities.User>(q =>
|
|
{
|
|
q.ToTable("Users");
|
|
|
|
q.HasKey(x => x.Id);
|
|
q.Property(x => x.NickName).IsRequired().HasMaxLength(32);
|
|
q.Property(x => x.FirstName).HasMaxLength(32);
|
|
q.Property(x => x.Patronymic).HasMaxLength(64);
|
|
q.Property(x => x.LastName).HasMaxLength(128);
|
|
q.Property(x => x.AvatarId).HasMaxLength(128);
|
|
|
|
q.HasOne(x => x.Account)
|
|
.WithOne(x => x.User)
|
|
.HasForeignKey<Account>(x => x.UserId);
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
|
|
q.OwnsOne(x => x.RegionalSettings);
|
|
});
|
|
modelBuilder.Entity<Entities.User>()
|
|
.Navigation(x => x.RegionalSettings).IsRequired(); //fix optional dependent
|
|
|
|
modelBuilder.Entity<Account>(q =>
|
|
{
|
|
q.ToTable("Accounts");
|
|
|
|
q.HasKey(x => x.Id);
|
|
q.Property(x => x.Email).IsRequired().HasMaxLength(128);
|
|
q.Property(x => x.HashedPassword).IsRequired().HasMaxLength(256);
|
|
|
|
q.HasMany(x => x.Sessions)
|
|
.WithOne()
|
|
.HasForeignKey(x => x.AccountId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
|
|
q.Property(x => x.CreationDate)
|
|
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
});
|
|
|
|
modelBuilder.Entity<Session>(q =>
|
|
{
|
|
//q.Property(q => q.DeviceInfo).HasMaxLength(128);
|
|
//q.Property(q => q.UserAgent).HasMaxLength(128);
|
|
q.OwnsOne(x => x.ClientInfo, x =>
|
|
{
|
|
x.Property(z => z.UserAgent).HasMaxLength(256);
|
|
x.Property(z => z.Country).HasMaxLength(96);
|
|
x.Property(z => z.Region).HasMaxLength(128);
|
|
});
|
|
q.Property(x => x.RefreshToken).IsRequired().HasMaxLength(172); //128 bytes to base64
|
|
// q.Property(x => x.ExpiredDate).HasDefaultValueSql("'0001-01-01 00:00:00+00'").ValueGeneratedOnAdd();
|
|
q.Property(x => x.ExpiredDate).HasDefaultValueSql("now()").ValueGeneratedOnAdd();
|
|
q.Property(x => x.LastUpdate).HasDefaultValueSql("now()").ValueGeneratedOnAdd();
|
|
});
|
|
|
|
modelBuilder.Entity<Permission>(q =>
|
|
{
|
|
q.ToTable("Permissions");
|
|
q.HasKey(x => x.Id);
|
|
|
|
q.Property(x => x.Code).IsRequired().HasMaxLength(128);
|
|
q.HasIndex(x => x.Code).IsUnique();
|
|
|
|
q.Property(x => x.Name).IsRequired().HasMaxLength(64);
|
|
q.Property(x => x.Description).HasMaxLength(512);
|
|
|
|
q.Property(x => x.CreationDate)
|
|
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
});
|
|
|
|
modelBuilder.Entity<Role>(q =>
|
|
{
|
|
q.ToTable("Roles");
|
|
q.HasKey(x => x.Id);
|
|
|
|
q.Property(x => x.Code).IsRequired().HasMaxLength(64);
|
|
q.HasIndex(x => x.Code).IsUnique();
|
|
|
|
q.Property(x => x.Name).IsRequired().HasMaxLength(32);
|
|
q.Property(x => x.Description).HasMaxLength(512);
|
|
|
|
q.Property(x => x.CreationDate)
|
|
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
|
|
q.HasMany(x => x.Permissions)
|
|
.WithMany(x => x.Roles)
|
|
.UsingEntity<Dictionary<string, object>>("RolePermissions",
|
|
x => x.HasOne<Permission>()
|
|
.WithMany()
|
|
.HasForeignKey("PermissionId")
|
|
.OnDelete(DeleteBehavior.Restrict)
|
|
, x => x.HasOne<Role>()
|
|
.WithMany()
|
|
.HasForeignKey("RoleId")
|
|
.OnDelete(DeleteBehavior.Restrict),
|
|
x =>
|
|
{
|
|
x.ToTable("RolePermissions");
|
|
x.HasKey("RoleId", "PermissionId");
|
|
});
|
|
});
|
|
|
|
modelBuilder.Entity<AccountRole>(q =>
|
|
{
|
|
q.ToTable("AccountRoles");
|
|
q.HasKey(x => x.Id);
|
|
|
|
q.Property(x => x.GrantedAtUtc)
|
|
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
|
|
|
|
q.Property(x => x.IssuerId).IsRequired();
|
|
q.Property(x => x.RevokedAtUtc).IsRequired(false);
|
|
q.Property(x => x.GrantReason).IsRequired(false).HasMaxLength(128);
|
|
q.Property(x => x.RevokeReason).IsRequired(false).HasMaxLength(128);
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
|
|
q.HasOne(x => x.Account)
|
|
.WithMany(a => a.Roles)
|
|
.HasForeignKey(x => x.AccountId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasOne(x => x.Role)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.RoleId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasOne(x => x.Issuer)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.IssuerId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasOne(x => x.Revoker)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.RevokerId)
|
|
.OnDelete(DeleteBehavior.Restrict)
|
|
.IsRequired(false);
|
|
|
|
q.HasIndex(x => new { x.AccountId, x.RoleId })
|
|
.HasDatabaseName("UX_AccountRoles_Active")
|
|
.IsUnique()
|
|
.HasFilter("\"RevokedAtUtc\" IS NULL");
|
|
|
|
q.HasIndex(x => new { x.AccountId, x.GrantedAtUtc });
|
|
q.HasIndex(x => new { x.IssuerId, x.GrantedAtUtc });
|
|
});
|
|
|
|
modelBuilder.Entity<AccountPermission>(q =>
|
|
{
|
|
q.ToTable("AccountPermissions");
|
|
q.HasKey(x => x.Id);
|
|
|
|
q.Property(x => x.GrantedAtUtc)
|
|
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
|
|
|
|
q.Property(x => x.IssuerId).IsRequired();
|
|
q.Property(x => x.RevokedAtUtc).IsRequired(false);
|
|
q.Property(x => x.GrantReason).IsRequired(false).HasMaxLength(128);
|
|
q.Property(x => x.RevokeReason).IsRequired(false).HasMaxLength(128);
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
|
|
q.HasOne(x => x.Account)
|
|
.WithMany(a => a.Permissions)
|
|
.HasForeignKey(x => x.AccountId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasOne(x => x.Permission)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.PermissionId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasOne(x => x.Issuer)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.IssuerId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasOne(x => x.Revoker)
|
|
.WithMany()
|
|
.HasForeignKey(x => x.RevokerId)
|
|
.OnDelete(DeleteBehavior.Restrict)
|
|
.IsRequired(false);
|
|
|
|
q.HasIndex(x => new { x.AccountId, x.PermissionId })
|
|
.HasDatabaseName("UX_AccountPermissions_Active")
|
|
.IsUnique()
|
|
.HasFilter("\"RevokedAtUtc\" IS NULL");
|
|
|
|
q.HasIndex(x => new { x.AccountId, x.GrantedAtUtc });
|
|
q.HasIndex(x => new { x.IssuerId, x.GrantedAtUtc });
|
|
});
|
|
|
|
modelBuilder.Entity<AccountBan>(q =>
|
|
{
|
|
q.ToTable("AccountBans");
|
|
q.HasKey(x => x.Id);
|
|
|
|
q.Property(x => x.BanDate)
|
|
.HasDefaultValueSql("now()").ValueGeneratedOnAdd().HasValueGenerator(typeof(DatetimeNowValueGenerator));
|
|
|
|
q.Property(x => x.IssuerId).IsRequired();
|
|
q.Property(x => x.Reason).IsRequired().HasMaxLength(128);
|
|
q.Property(x => x.UnbanReason).IsRequired(false).HasMaxLength(128);
|
|
|
|
q.Property(e => e.Xmin).HasColumnName("xmin").IsRowVersion();
|
|
|
|
q.HasOne(x => x.Account)
|
|
.WithMany(a => a.Bans)
|
|
.HasForeignKey(x => x.AccountId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
|
|
q.HasIndex(x => new { x.AccountId, x.BanDate });
|
|
// q.HasIndex(x => new { x.AccountId, x.ReleaseDate })
|
|
// .HasDatabaseName("IX_AccountBans_Active")
|
|
// .HasFilter("\"Deleted\" = false AND (\"ReleaseDate\" IS NULL OR \"ReleaseDate\" > now())");
|
|
});
|
|
|
|
RolesAndPermissionSeedList.SeedPermissions(modelBuilder.Entity<Permission>());
|
|
RolesAndPermissionSeedList.SeedRoles(modelBuilder.Entity<Role>(), modelBuilder);
|
|
|
|
modelBuilder.Entity<Account>().HasQueryFilter(x => !x.Deleted);
|
|
modelBuilder.Entity<AccountPermission>().HasQueryFilter(x => !x.Account.Deleted);
|
|
modelBuilder.Entity<AccountRole>().HasQueryFilter(x => !x.Account.Deleted);
|
|
|
|
modelBuilder.Entity<AccountBan>().HasQueryFilter(x => !x.Deleted);
|
|
modelBuilder.Entity<Role>().HasQueryFilter(x => !x.Deleted);
|
|
modelBuilder.Entity<Permission>().HasQueryFilter(x => !x.Deleted);
|
|
|
|
}
|
|
|
|
private class DatetimeNowValueGenerator : ValueGenerator<DateTime>
|
|
{
|
|
public override bool GeneratesTemporaryValues => false;
|
|
|
|
public override DateTime Next(EntityEntry entry)
|
|
{
|
|
return DateTime.UtcNow;
|
|
}
|
|
}
|
|
} |