diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs new file mode 100644 index 00000000..0f41cdce --- /dev/null +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/IPasswordRuleProvider.cs @@ -0,0 +1,25 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Contracts.Admin.Infrastructure.Password; + +/// +/// Resolves the effective password rule for a given client and validates passwords against it. +/// A client-level rule (stored on ClientConfig) takes precedence; when absent it falls back to +/// the global DCC configuration. +/// +public interface IPasswordRuleProvider +{ + /// + /// Validate a password against the client's effective rule. + /// Returns the localized failure prompt, or null when the password is valid. + /// Designed to be called from a FluentValidation rule (see ) + /// so client-aware password validation stays inside the single, framework-invoked validation pipeline. + /// + Task GetFailureAsync(string? password, string? clientId); + + /// + /// Generate a new password satisfying the global DCC password rule. + /// + Task GenerateNewPasswordAsync(); +} diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordHelper.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordHelper.cs deleted file mode 100644 index 29d5292c..00000000 --- a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordHelper.cs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) MASA Stack All rights reserved. -// Licensed under the Apache License. See LICENSE.txt in the project root for license information. - -namespace Masa.Auth.Contracts.Admin.Infrastructure.Password; - -public class PasswordHelper : ISingletonDependency -{ - public const string PASSWORDRULECONFIGNAME = "$public.AppSettings:PasswordRule"; - public const string PASSWORDPROMPTCONFIGNAME = "$public.AppSettings:PasswordPrompt"; - public const string DEFAULTPASSWORDRULE = "^\\S*(?=\\S{6,})(?=\\S*\\d)(?=\\S*[A-Za-z])\\S*$"; - public const string DEFAULTPASSWORDPROMPT = "PasswordValidateFailed"; - - private readonly IMasaConfiguration _masaConfiguration; - private readonly ILogger _logger; - - public PasswordHelper(IMasaConfiguration masaConfiguration, ILogger logger) - { - _masaConfiguration = masaConfiguration; - _logger = logger; - } - - /// - /// 生成新的密码 - /// - /// 生成的密码 - public string GenerateNewPassword() - { - try - { - var (passwordRule, _) = GetPasswordRule(); - var xeger = new Xeger(passwordRule); - return xeger.Generate(); - } - catch (Exception ex) - { - _logger.LogError(ex, "生成新密码时发生错误"); - // 如果生成失败,返回默认密码规则生成的密码 - try - { - var defaultXeger = new Xeger(DEFAULTPASSWORDRULE); - return defaultXeger.Generate(); - } - catch (Exception fallbackEx) - { - _logger.LogError(fallbackEx, "使用默认密码规则生成密码时也发生错误"); - throw new InvalidOperationException("无法生成密码", fallbackEx); - } - } - } - - /// - /// 获取密码规则和提示信息 - /// - /// 密码规则和提示信息的元组 - public (string rule, string prompt) GetPasswordRule() - { - var passwordRule = DEFAULTPASSWORDRULE; - var passwordPrompt = DEFAULTPASSWORDPROMPT; - if (_masaConfiguration != null) - { - try - { - passwordRule = _masaConfiguration.ConfigurationApi.GetPublic().GetValue(PASSWORDRULECONFIGNAME, DEFAULTPASSWORDRULE); - passwordPrompt = _masaConfiguration.ConfigurationApi.GetPublic().GetValue(PASSWORDPROMPTCONFIGNAME, DEFAULTPASSWORDPROMPT); - } - catch (Exception ex) - { - _logger.LogError(ex, "获取密码规则配置时发生错误,使用默认配置。配置名称: {PasswordRuleConfigName}, {PasswordPromptConfigName}", - PASSWORDRULECONFIGNAME, PASSWORDPROMPTCONFIGNAME); - } - } - else - { - _logger.LogWarning("MasaConfiguration 为空,使用默认密码规则配置"); - } - return (passwordRule, passwordPrompt); - } - - /// - /// 验证密码格式 - /// - /// 待验证的密码 - /// 验证上下文 - public void ValidatePassword(string? password, ValidationContext context) - { - if (password == null) - { - password = string.Empty; - } - - try - { - var (passwordRule, passwordPrompt) = GetPasswordRule(); - if (!Regex.IsMatch(password, passwordRule)) - { - _logger.LogWarning("密码验证失败,密码不符合规则。规则: {PasswordRule}", passwordRule); - var message = DEFAULTPASSWORDRULE.Equals(passwordRule) ? "PasswordFormatVerificationPrompt" : passwordPrompt; - try - { - message = I18n.T(message); - } - catch (Exception i18nEx) - { - _logger.LogWarning(i18nEx, "获取密码验证失败提示的本地化文本时发生错误,消息键: {MessageKey}", message); - } - finally - { - context.AddFailure(message); - } - } - } - catch (Exception ex) - { - _logger.LogError(ex, "密码验证过程中发生异常"); - context.AddFailure("密码验证过程中发生错误"); - } - } -} \ No newline at end of file diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs new file mode 100644 index 00000000..e3da97f2 --- /dev/null +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Infrastructure/Password/PasswordRuleValidatorExtensions.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Contracts.Admin.Infrastructure.Password; + +/// +/// Wires into a FluentValidation rule chain. The configured +/// rule (global DCC default, or a client override) is the single source of truth for what a valid +/// password looks like - no hardcoded required/length checks are layered on top of it here. +/// +public static class PasswordRuleValidatorExtensions +{ + public static IRuleBuilderOptionsConditions PasswordRule( + this IRuleBuilder ruleBuilder, + IPasswordRuleProvider passwordRuleProvider, + Func clientId) + { + return ruleBuilder.CustomAsync(async (password, context, cancellation) => + { + var failure = await passwordRuleProvider.GetFailureAsync(password, clientId(context.InstanceToValidate)); + if (failure is not null) + { + context.AddFailure(failure); + } + }); + } +} diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientConfigDto.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientConfigDto.cs new file mode 100644 index 00000000..1eb5b4ac --- /dev/null +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientConfigDto.cs @@ -0,0 +1,30 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Contracts.Admin.Sso; + +public class ClientConfigDto +{ + /// + /// OIDC client_id + /// + public string ClientId { get; set; } = ""; + + /// + /// 密码规则(正则表达式);为空表示回退到全局 DCC 配置 + /// + public ClientPasswordRuleDto PasswordRule { get; set; } = new(); + + /// + /// 密码验证失败提示(i18n key);为空表示回退到全局 DCC 配置 + /// + /// + /// 短信场景 × 渠道 × 模板配置 + /// + public List SmsTemplates { get; set; } = new(); + + /// + /// 邮件场景 × 渠道 × 模板配置 + /// + public List EmailTemplates { get; set; } = new(); +} diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientDetailDto.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientDetailDto.cs index 9eb1c9bf..2dc02026 100644 --- a/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientDetailDto.cs +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientDetailDto.cs @@ -82,4 +82,24 @@ public class ClientDetailDto : AddClientDto #region Properties public List Properties { get; set; } = new(); #endregion + + #region Password & Message Templates + /// + /// 密码规则(正则表达式);为空表示回退到全局 DCC 配置 + /// + public ClientPasswordRuleDto PasswordRule { get; set; } = new(); + + /// + /// 密码验证失败提示(i18n key);为空表示回退到全局 DCC 配置 + /// + /// + /// 短信场景 × 渠道 × 模板配置 + /// + public List SmsTemplates { get; set; } = new(); + + /// + /// 邮件场景 × 渠道 × 模板配置 + /// + public List EmailTemplates { get; set; } = new(); + #endregion } diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientEmailTemplateDto.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientEmailTemplateDto.cs new file mode 100644 index 00000000..4d2604d6 --- /dev/null +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientEmailTemplateDto.cs @@ -0,0 +1,22 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Contracts.Admin.Sso; + +/// +/// Client 级邮件模板配置:一个发送场景对应一个渠道 + 模板 +/// +public class ClientEmailTemplateDto +{ + public SendEmailTypes Scene { get; set; } + + /// + /// MC 渠道编码 + /// + public string ChannelCode { get; set; } = ""; + + /// + /// MC 模板编码 + /// + public string TemplateCode { get; set; } = ""; +} diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientPasswordRuleDto.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientPasswordRuleDto.cs new file mode 100644 index 00000000..ac29715e --- /dev/null +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientPasswordRuleDto.cs @@ -0,0 +1,25 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Contracts.Admin.Sso; + +public class ClientPasswordRuleDto +{ + public bool UseRegexPattern { get; set; } + + public int MinLength { get; set; } = 6; + + public int MaxLength { get; set; } = 20; + + public bool RequireUppercase { get; set; } + + public bool RequireLowercase { get; set; } + + public bool RequireDigit { get; set; } + + public bool RequireSpecialCharacter { get; set; } + + public string RegexPattern { get; set; } = string.Empty; + + public string? PasswordPrompt { get; set; } +} diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientSmsTemplateDto.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientSmsTemplateDto.cs new file mode 100644 index 00000000..be6576be --- /dev/null +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Sso/ClientSmsTemplateDto.cs @@ -0,0 +1,22 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Contracts.Admin.Sso; + +/// +/// Client 级短信模板配置:一个发送场景对应一个渠道 + 模板 +/// +public class ClientSmsTemplateDto +{ + public SendMsgCodeTypes Scene { get; set; } + + /// + /// MC 渠道编码 + /// + public string ChannelCode { get; set; } = ""; + + /// + /// MC 模板编码 + /// + public string TemplateCode { get; set; } = ""; +} diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Subjects/Validator/PasswordValidator.cs b/src/Contracts/Masa.Auth.Contracts.Admin/Subjects/Validator/PasswordValidator.cs index 643dab0f..4e429518 100644 --- a/src/Contracts/Masa.Auth.Contracts.Admin/Subjects/Validator/PasswordValidator.cs +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Subjects/Validator/PasswordValidator.cs @@ -5,8 +5,16 @@ namespace Masa.Auth.Contracts.Admin.Subjects.Validator; public class PasswordValidator : MasaAbstractValidator { - public PasswordValidator(PasswordHelper passwordHelper) + public PasswordValidator(IPasswordRuleProvider passwordRuleProvider) { - RuleFor(password => password).Required().MaximumLength(50).Custom(passwordHelper.ValidatePassword); + RuleFor(password => password).Required() + .CustomAsync(async (password, context, cancellation) => + { + var failure = await passwordRuleProvider.GetFailureAsync(password, null); + if (failure is not null) + { + context.AddFailure(failure); + } + }); } } diff --git a/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientConfig.cs b/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientConfig.cs new file mode 100644 index 00000000..1db4c775 --- /dev/null +++ b/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientConfig.cs @@ -0,0 +1,46 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Domain.Sso.Aggregates; + +/// +/// Per-client business configuration: password rule and the message template +/// matrix (scene x channel x template). Keyed by the OIDC client_id (string). +/// A missing value means "fall back to the global DCC configuration". +/// +public class ClientConfig : FullAggregateRoot +{ + private List _messageTemplates = new(); + + public string ClientId { get; private set; } = ""; + + public string? PasswordRule { get; private set; } + + public string? PasswordPrompt { get; private set; } + + public ClientPasswordRuleConfig? PasswordRuleConfig { get; private set; } + + public IReadOnlyCollection MessageTemplates => _messageTemplates; + + private ClientConfig() { } + + public ClientConfig(string clientId) + { + ClientId = clientId; + } + + public void UpdatePasswordRule(string? passwordRule, string? passwordPrompt, ClientPasswordRuleConfig? passwordRuleConfig) + { + PasswordRule = passwordRule; + PasswordPrompt = passwordPrompt; + PasswordRuleConfig = passwordRuleConfig; + } + + /// + /// Replace the whole message template matrix. + /// + public void SetMessageTemplates(IEnumerable messageTemplates) + { + _messageTemplates = messageTemplates.ToList(); + } +} \ No newline at end of file diff --git a/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientMessageTemplate.cs b/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientMessageTemplate.cs new file mode 100644 index 00000000..7d724537 --- /dev/null +++ b/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientMessageTemplate.cs @@ -0,0 +1,32 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +using Masa.BuildingBlocks.StackSdks.Mc.Enum; + +namespace Masa.Auth.Domain.Sso.Aggregates; + +/// +/// Client-level message template binding for a single (channel type, scene). +/// Scene stores the value of SendMsgCodeTypes (when ChannelType is Sms) or +/// SendEmailTypes (when ChannelType is Email); ChannelType disambiguates the two. +/// +public class ClientMessageTemplate : Entity +{ + public int ClientConfigId { get; private set; } + + public ChannelTypes ChannelType { get; private set; } + + public int Scene { get; private set; } + + public string ChannelCode { get; private set; } = ""; + + public string TemplateCode { get; private set; } = ""; + + public ClientMessageTemplate(ChannelTypes channelType, int scene, string channelCode, string templateCode) + { + ChannelType = channelType; + Scene = scene; + ChannelCode = channelCode; + TemplateCode = templateCode; + } +} diff --git a/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientPasswordRuleConfig.cs b/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientPasswordRuleConfig.cs new file mode 100644 index 00000000..b996bc52 --- /dev/null +++ b/src/Domain/Masa.Auth.Domain/Sso/Aggregates/ClientPasswordRuleConfig.cs @@ -0,0 +1,41 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Domain.Sso.Aggregates; + +public class ClientPasswordRuleConfig +{ + public int MinLength { get; set; } = 6; + + public int MaxLength { get; set; } = 32; + + public bool RequireUppercase { get; set; } + + public bool RequireLowercase { get; set; } + + public bool RequireDigit { get; set; } + + public bool RequireSpecialCharacter { get; set; } + + public bool UseRegexPattern { get; set; } + + public string RegexPattern { get; set; } = string.Empty; + + public string? PasswordPrompt { get; set; } + + public ClientPasswordRuleConfig Clone() + { + return new ClientPasswordRuleConfig + { + MinLength = MinLength, + MaxLength = MaxLength, + RequireUppercase = RequireUppercase, + RequireLowercase = RequireLowercase, + RequireDigit = RequireDigit, + RequireSpecialCharacter = RequireSpecialCharacter, + UseRegexPattern = UseRegexPattern, + RegexPattern = RegexPattern, + PasswordPrompt = PasswordPrompt + }; + } +} \ No newline at end of file diff --git a/src/Domain/Masa.Auth.Domain/Sso/Repositories/IClientConfigRepository.cs b/src/Domain/Masa.Auth.Domain/Sso/Repositories/IClientConfigRepository.cs new file mode 100644 index 00000000..bac37056 --- /dev/null +++ b/src/Domain/Masa.Auth.Domain/Sso/Repositories/IClientConfigRepository.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Domain.Sso.Repositories; + +public interface IClientConfigRepository : IRepository +{ + Task FindByClientIdAsync(string clientId); +} diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/EntityConfigurations/Sso/ClientConfigEntityTypeConfiguration.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/EntityConfigurations/Sso/ClientConfigEntityTypeConfiguration.cs new file mode 100644 index 00000000..e4b187f3 --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/EntityConfigurations/Sso/ClientConfigEntityTypeConfiguration.cs @@ -0,0 +1,45 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +using System.Text.Json; +using Masa.BuildingBlocks.StackSdks.Mc.Enum; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace Masa.Auth.EntityFrameworkCore.PostgreSql.EntityConfigurations.Sso; + +public class ClientConfigEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.ClientId).HasMaxLength(200).IsRequired(); + // Soft delete (IsDeleted) leaves the row in place, so the unique index must exclude + // deleted rows - otherwise a client can never be reconfigured after its config is removed. + builder.HasIndex(x => x.ClientId).IsUnique().HasFilter("NOT \"IsDeleted\""); + builder.Property(x => x.PasswordRule).HasMaxLength(500); + builder.Property(x => x.PasswordPrompt).HasMaxLength(500); + builder.Property(x => x.PasswordRuleConfig) + .HasConversion( + v => v == null ? null : JsonSerializer.Serialize(v, (JsonSerializerOptions?)null), + v => string.IsNullOrWhiteSpace(v) + ? null + : JsonSerializer.Deserialize(v, (JsonSerializerOptions?)null)) + .Metadata.SetValueComparer(new ValueComparer( + (l, r) => JsonSerializer.Serialize(l, (JsonSerializerOptions?)null) == JsonSerializer.Serialize(r, (JsonSerializerOptions?)null), + v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null).GetHashCode(), + v => v == null ? null : v.Clone())); + builder.Property(x => x.PasswordRuleConfig).HasMaxLength(2000); + builder.HasMany(x => x.MessageTemplates).WithOne().HasForeignKey(x => x.ClientConfigId); + } +} + +public class ClientMessageTemplateEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.ChannelCode).HasMaxLength(200).IsRequired(); + builder.Property(x => x.TemplateCode).HasMaxLength(200).IsRequired(); + builder.HasIndex(x => new { x.ClientConfigId, x.ChannelType, x.Scene }).IsUnique(); + } +} \ No newline at end of file diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Masa.Auth.EntityFrameworkCore.PostgreSql.csproj b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Masa.Auth.EntityFrameworkCore.PostgreSql.csproj index 6f861aaa..2f76bfb1 100644 --- a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Masa.Auth.EntityFrameworkCore.PostgreSql.csproj +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Masa.Auth.EntityFrameworkCore.PostgreSql.csproj @@ -10,7 +10,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/20260703082647_AddClientConfig.Designer.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/20260703082647_AddClientConfig.Designer.cs new file mode 100644 index 00000000..df279a3e --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/20260703082647_AddClientConfig.Designer.cs @@ -0,0 +1,3474 @@ +// +using System; +using Masa.Auth.Domain.Subjects.Aggregates; +using Masa.Auth.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Masa.Auth.EntityFrameworkCore.PostgreSql.Migrations +{ + [DbContext(typeof(AuthDbContext))] + [Migration("20260703082647_AddClientConfig")] + partial class AddClientConfig + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("auth") + .HasAnnotation("ProductVersion", "10.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique() + .HasFilter("NOT \"IsDeleted\""); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceFlowCodes", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.ToTable("DynamicRole", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.GlobalNavs.Aggregates.GlobalNavVisible", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Visible") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AppId"); + + b.HasIndex("ClientId"); + + b.ToTable("GlobalNavVisible", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Logs.Aggregates.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OperationDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("OperationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("OperationType") + .HasColumnType("integer"); + + b.Property("Operator") + .HasColumnType("uuid"); + + b.Property("OperatorName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("OperationDescription"); + + b.HasIndex("OperationTime"); + + b.HasIndex("OperationType"); + + b.HasIndex("Operator"); + + b.ToTable("OperationLog", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.Department", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Level") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("Sort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("Name", "ParentId"); + + b.ToTable("Department", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.DepartmentStaff", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("DepartmentId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("StaffId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DepartmentId"); + + b.HasIndex("StaffId"); + + b.ToTable("DepartmentStaff", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.Position", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Position", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Icon") + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Legend") + .HasColumnType("text"); + + b.Property("MatchPattern") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("SystemId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("SystemId", "AppId", "Code"); + + b.ToTable("Permission", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.PermissionRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AffiliationPermissionId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LeadingPermissionId") + .HasColumnType("uuid"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AffiliationPermissionId"); + + b.HasIndex("LeadingPermissionId", "AffiliationPermissionId"); + + b.ToTable("PermissionRelation", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AvailableQuantity") + .HasColumnType("integer"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Limit") + .HasColumnType("integer"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(2); + + b.HasKey("Id"); + + b.ToTable("Role", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleClient", b => + { + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("RoleId", "ClientId"); + + b.ToTable("RoleClient", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleRelation", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Effect") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("PermissionId") + .HasColumnType("uuid"); + + b.Property("_businessType") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.HasKey("Id"); + + b.ToTable("SubjectPermissionRelation", "auth"); + + b.HasDiscriminator("_businessType").HasValue("SubjectPermissionRelation"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("PasswordPrompt") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PasswordRule") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PasswordRuleConfig") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("NOT \"IsDeleted\""); + + b.ToTable("ClientConfig", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ChannelType") + .HasColumnType("integer"); + + b.Property("ClientConfigId") + .HasColumnType("integer"); + + b.Property("Scene") + .HasColumnType("integer"); + + b.Property("TemplateCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientConfigId", "ChannelType", "Scene") + .IsUnique(); + + b.ToTable("ClientMessageTemplate", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Creator"); + + b.HasIndex("Modifier"); + + b.HasIndex("Name"); + + b.ToTable("CustomLogin", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLoginThirdPartyIdp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomLoginId") + .HasColumnType("integer"); + + b.Property("Sort") + .HasColumnType("integer"); + + b.Property("ThirdPartyIdpId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CustomLoginId"); + + b.HasIndex("ThirdPartyIdpId"); + + b.ToTable("CustomLoginThirdPartyIdp", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.RegisterField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomLoginId") + .HasColumnType("integer"); + + b.Property("RegisterFieldType") + .HasColumnType("integer"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("Sort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CustomLoginId"); + + b.ToTable("RegisterField", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.UserClaimExtend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DataSourceType") + .HasColumnType("integer"); + + b.Property("DataSourceValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("ItemText") + .IsRequired() + .HasColumnType("text"); + + b.Property("ItemValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserClaimId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("UserClaimExtend", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Icon") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ThirdPartyIdpType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("IdentityProvider", "auth"); + + b.HasDiscriminator("Discriminator").HasValue("IdentityProvider"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Avatar") + .IsRequired() + .HasColumnType("text"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("CurrentTeamId") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Gender") + .HasColumnType("integer"); + + b.Property("IdCard") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("JobNumber") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("PositionId") + .HasColumnType("uuid"); + + b.Property("StaffType") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrentTeamId"); + + b.HasIndex("JobNumber"); + + b.HasIndex("PositionId"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Staff", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TeamType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Team", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("TeamMemberType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamRole", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamStaff", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("StaffId") + .HasColumnType("uuid"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("TeamMemberType") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("StaffId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamStaff", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClaimData") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExtendedData") + .IsRequired() + .HasColumnType("text"); + + b.Property("IdentityProviderId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("ThirdPartyIdpId") + .HasColumnType("uuid"); + + b.Property("ThridPartyIdentity") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("IdentityProviderId"); + + b.HasIndex("ThirdPartyIdpId"); + + b.HasIndex("UserId"); + + b.HasIndex("CreationTime", "ModificationTime"); + + b.ToTable("ThirdPartyUser", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Account") + .IsRequired() + .HasColumnType("text"); + + b.Property("Avatar") + .IsRequired() + .HasColumnType("text"); + + b.Property("ClientId") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasDefaultValue(""); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Department") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Gender") + .HasColumnType("integer"); + + b.Property("IdCard") + .IsRequired() + .HasMaxLength(18) + .HasColumnType("character varying(18)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Landline") + .IsRequired() + .HasColumnType("text"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(11) + .HasColumnType("character varying(11)"); + + b.Property("Position") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Account"); + + b.HasIndex("ClientId"); + + b.HasIndex("Email"); + + b.HasIndex("IdCard"); + + b.HasIndex("Name"); + + b.HasIndex("PhoneNumber"); + + b.HasIndex("CreationTime", "ModificationTime"); + + b.ToTable("User", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserClaimValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaimValue", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("UserRole", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserSystemBusinessData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("SystemId") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "SystemId"); + + b.ToTable("UserSystemBusinessData", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Event") + .IsRequired() + .HasColumnType("text"); + + b.Property("HttpMethod") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Secret") + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Webhook", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.WebhookLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("WebhookId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookLog", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowedAccessTokenSigningAlgorithms") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastAccessed") + .HasColumnType("timestamp with time zone"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("NonEditable") + .HasColumnType("boolean"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("NOT \"IsDeleted\""); + + b.ToTable("ApiResource", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApiResourceId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("UserClaimId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.HasIndex("UserClaimId"); + + b.ToTable("ApiResourceClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApiResourceId") + .HasColumnType("uuid"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApiResourceId") + .HasColumnType("uuid"); + + b.Property("ApiScopeId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.HasIndex("ApiScopeId"); + + b.ToTable("ApiResourceScope", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApiResourceId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecret", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Emphasize") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiScope", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApiScopeId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("UserClaimId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ApiScopeId"); + + b.HasIndex("UserClaimId"); + + b.ToTable("ApiScopeClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("ScopeId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("integer"); + + b.Property("AccessTokenLifetime") + .HasColumnType("integer"); + + b.Property("AccessTokenType") + .HasColumnType("integer"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("boolean"); + + b.Property("AllowOfflineAccess") + .HasColumnType("boolean"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("boolean"); + + b.Property("AllowRememberConsent") + .HasColumnType("boolean"); + + b.Property("AllowedIdentityTokenSigningAlgorithms") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("boolean"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("boolean"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("integer"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("boolean"); + + b.Property("BackChannelLogoutUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ClientClaimsPrefix") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientType") + .HasColumnType("integer"); + + b.Property("ClientUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ConsentLifetime") + .HasColumnType("integer"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("DeviceCodeLifetime") + .HasColumnType("integer"); + + b.Property("EnableLocalLogin") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("boolean"); + + b.Property("FrontChannelLogoutUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("IdentityTokenLifetime") + .HasColumnType("integer"); + + b.Property("IncludeJwtId") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastAccessed") + .HasColumnType("timestamp with time zone"); + + b.Property("LogoUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("NonEditable") + .HasColumnType("boolean"); + + b.Property("PairWiseSubjectSalt") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ProtocolType") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RefreshTokenExpiration") + .HasColumnType("integer"); + + b.Property("RefreshTokenUsage") + .HasColumnType("integer"); + + b.Property("RequireClientSecret") + .HasColumnType("boolean"); + + b.Property("RequireConsent") + .HasColumnType("boolean"); + + b.Property("RequirePkce") + .HasColumnType("boolean"); + + b.Property("RequireRequestObject") + .HasColumnType("boolean"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("integer"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("boolean"); + + b.Property("UserCodeType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UserSsoLifetime") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("NOT \"IsDeleted\""); + + b.ToTable("Client", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientCorsOrigin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("Origin") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientCorsOrigin", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientGrantType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("GrantType") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientGrantType", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientIdPRestriction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientIdPRestriction", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientPostLogoutRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("PostLogoutRedirectUri") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientPostLogoutRedirectUri", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("RedirectUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientRedirectUri", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("Scope") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientScope", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientSecret", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Emphasize") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("NonEditable") + .HasColumnType("boolean"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("NOT \"IsDeleted\""); + + b.ToTable("IdentityResource", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IdentityResourceId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("UserClaimId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.HasIndex("UserClaimId"); + + b.ToTable("IdentityResourceClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IdentityResourceId") + .HasColumnType("uuid"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.ToTable("UserClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Dispatcher.IntegrationEvents.Logs.IntegrationEventLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("EventId") + .HasColumnType("uuid"); + + b.Property("EventTypeName") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExpandContent") + .IsRequired() + .HasColumnType("text"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(36) + .HasColumnType("character varying(36)") + .HasColumnName("RowVersion"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TimesSent") + .HasColumnType("integer"); + + b.Property("TransactionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex(new[] { "EventId", "RowVersion" }, "IX_EventId_Version"); + + b.HasIndex(new[] { "State", "ModificationTime" }, "IX_State_MTime"); + + b.HasIndex(new[] { "State", "TimesSent", "ModificationTime" }, "IX_State_TimesSent_MTime"); + + b.ToTable("IntegrationEventLog", "auth"); + }); + + modelBuilder.Entity("PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrant", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RolePermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasIndex("PermissionId"); + + b.HasIndex("RoleId"); + + b.HasDiscriminator().HasValue("Role"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("TeamMemberType") + .HasColumnType("integer"); + + b.HasIndex("PermissionId"); + + b.HasIndex("TeamId"); + + b.HasDiscriminator().HasValue("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasIndex("PermissionId"); + + b.HasIndex("UserId"); + + b.HasDiscriminator().HasValue("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.LdapIdp", b => + { + b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); + + b.Property("BaseDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("GroupSearchBaseDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsSSL") + .HasColumnType("boolean"); + + b.Property("RootUserDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RootUserPassword") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ServerAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerPort") + .HasColumnType("integer"); + + b.Property("UserSearchBaseDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasDiscriminator().HasValue("LDAP"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyIdp", b => + { + b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); + + b.Property("AuthenticationType") + .HasColumnType("integer"); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("text"); + + b.Property("CallbackPath") + .IsRequired() + .HasColumnType("text"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ClientSecret") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("JsonKeyMap") + .IsRequired() + .HasColumnType("text"); + + b.Property("MapAll") + .HasColumnType("boolean"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserInformationEndpoint") + .IsRequired() + .HasColumnType("text"); + + b.HasDiscriminator().HasValue("ThirdParty"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRole", b => + { + b.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ControlPolicy", "ControlPolicies", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b1.Property("DynamicRoleId") + .HasColumnType("uuid"); + + b1.Property("Effect") + .HasColumnType("integer"); + + b1.Property("Enabled") + .HasColumnType("boolean"); + + b1.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b1.Property("Priority") + .HasColumnType("integer"); + + b1.HasKey("Id"); + + b1.HasIndex("DynamicRoleId"); + + b1.ToTable("ControlPolicy", "auth"); + + b1.WithOwner() + .HasForeignKey("DynamicRoleId"); + + b1.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ActionIdentifier", "Actions", b2 => + { + b2.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b2.Property("ControlPolicyId") + .HasColumnType("uuid"); + + b2.Property("Operation") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b2.Property("Resource") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b2.Property("Type") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b2.HasKey("Id"); + + b2.HasIndex("ControlPolicyId"); + + b2.ToTable("ActionIdentifier", "auth"); + + b2.WithOwner() + .HasForeignKey("ControlPolicyId"); + }); + + b1.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ResourceIdentifier", "Resources", b2 => + { + b2.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b2.Property("ControlPolicyId") + .HasColumnType("uuid"); + + b2.Property("Identifier") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b2.Property("Region") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b2.Property("Service") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b2.HasKey("Id"); + + b2.HasIndex("ControlPolicyId"); + + b2.ToTable("ResourceIdentifier", "auth"); + + b2.WithOwner() + .HasForeignKey("ControlPolicyId"); + }); + + b1.Navigation("Actions"); + + b1.Navigation("Resources"); + }); + + b.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRuleCondition", "Conditions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b1.Property("DataType") + .HasColumnType("integer"); + + b1.Property("DynamicRoleId") + .HasColumnType("uuid"); + + b1.Property("FieldName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b1.Property("LogicalOperator") + .HasColumnType("integer"); + + b1.Property("OperatorType") + .HasColumnType("integer"); + + b1.Property("Order") + .HasColumnType("integer"); + + b1.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("Id"); + + b1.HasIndex("DynamicRoleId"); + + b1.ToTable("DynamicRuleCondition", "auth"); + + b1.WithOwner() + .HasForeignKey("DynamicRoleId"); + }); + + b.Navigation("Conditions"); + + b.Navigation("ControlPolicies"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.DepartmentStaff", b => + { + b.HasOne("Masa.Auth.Domain.Organizations.Aggregates.Department", "Department") + .WithMany("DepartmentStaffs") + .HasForeignKey("DepartmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Staff", "Staff") + .WithMany("DepartmentStaffs") + .HasForeignKey("StaffId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Department"); + + b.Navigation("Staff"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Permission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.PermissionRelation", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "AffiliationPermission") + .WithMany("LeadingPermissionRelations") + .HasForeignKey("AffiliationPermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "LeadingPermission") + .WithMany("AffiliationPermissionRelations") + .HasForeignKey("LeadingPermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AffiliationPermission"); + + b.Navigation("LeadingPermission"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleClient", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", null) + .WithMany("Clients") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleRelation", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "ParentRole") + .WithMany("ChildrenRoles") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("ParentRoles") + .HasForeignKey("RoleId") + .IsRequired(); + + b.Navigation("ParentRole"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", null) + .WithMany("MessageTemplates") + .HasForeignKey("ClientConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "CreateUser") + .WithMany() + .HasForeignKey("Creator"); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "ModifyUser") + .WithMany() + .HasForeignKey("Modifier"); + + b.Navigation("CreateUser"); + + b.Navigation("ModifyUser"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLoginThirdPartyIdp", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", null) + .WithMany("ThirdPartyIdps") + .HasForeignKey("CustomLoginId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyIdp", "ThirdPartyIdp") + .WithMany() + .HasForeignKey("ThirdPartyIdpId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ThirdPartyIdp"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.RegisterField", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", null) + .WithMany("RegisterFields") + .HasForeignKey("CustomLoginId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "CurrentTeam") + .WithMany() + .HasForeignKey("CurrentTeamId"); + + b.HasOne("Masa.Auth.Domain.Organizations.Aggregates.Position", "Position") + .WithMany() + .HasForeignKey("PositionId"); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithOne("Staff") + .HasForeignKey("Masa.Auth.Domain.Subjects.Aggregates.Staff", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Masa.Auth.Domain.Subjects.Aggregates.AddressValue", "Address", b1 => + { + b1.Property("StaffId") + .HasColumnType("uuid"); + + b1.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b1.Property("CityCode") + .IsRequired() + .HasColumnType("text"); + + b1.Property("DistrictCode") + .IsRequired() + .HasColumnType("text"); + + b1.Property("ProvinceCode") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("StaffId"); + + b1.ToTable("Staff", "auth"); + + b1.WithOwner() + .HasForeignKey("StaffId"); + }); + + b.Navigation("Address") + .IsRequired(); + + b.Navigation("CurrentTeam"); + + b.Navigation("Position"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Team", b => + { + b.OwnsOne("Masa.Auth.Domain.Subjects.Aggregates.AvatarValue", "Avatar", b1 => + { + b1.Property("TeamId") + .HasColumnType("uuid"); + + b1.Property("Color") + .IsRequired() + .HasColumnType("text"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b1.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("TeamId"); + + b1.ToTable("Team", "auth"); + + b1.WithOwner() + .HasForeignKey("TeamId"); + }); + + b.Navigation("Avatar") + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamRole", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("Teams") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "Team") + .WithMany("TeamRoles") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamStaff", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Staff", "Staff") + .WithMany("TeamStaffs") + .HasForeignKey("StaffId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "Team") + .WithMany("TeamStaffs") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Staff"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyUser", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", null) + .WithMany("ThirdPartyUsers") + .HasForeignKey("IdentityProviderId"); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", "IdentityProvider") + .WithMany() + .HasForeignKey("ThirdPartyIdpId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("ThirdPartyUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IdentityProvider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.User", b => + { + b.OwnsOne("Masa.Auth.Domain.Subjects.Aggregates.AddressValue", "Address", b1 => + { + b1.Property("UserId") + .HasColumnType("uuid"); + + b1.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b1.Property("CityCode") + .IsRequired() + .HasColumnType("text"); + + b1.Property("DistrictCode") + .IsRequired() + .HasColumnType("text"); + + b1.Property("ProvinceCode") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("UserId"); + + b1.ToTable("User", "auth"); + + b1.WithOwner() + .HasForeignKey("UserId"); + }); + + b.Navigation("Address") + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserClaimValue", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("UserClaims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserRole", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("Users") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserSystemBusinessData", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("SystemBusinessDatas") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.WebhookLog", b => + { + b.HasOne("Masa.Auth.Domain.Webhooks.Aggregates.Webhook", "Webhook") + .WithMany("WebhookLogs") + .HasForeignKey("WebhookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Webhook"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", "UserClaim") + .WithMany() + .HasForeignKey("UserClaimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + + b.Navigation("UserClaim"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceScope", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("ApiScopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", "ApiScope") + .WithMany() + .HasForeignKey("ApiScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + + b.Navigation("ApiScope"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceSecret", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", "ApiScope") + .WithMany("UserClaims") + .HasForeignKey("ApiScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", "UserClaim") + .WithMany() + .HasForeignKey("UserClaimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiScope"); + + b.Navigation("UserClaim"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scope"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientCorsOrigin", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientGrantType", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientIdPRestriction", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientRedirectUri", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientScope", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientSecret", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", "IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", "UserClaim") + .WithMany() + .HasForeignKey("UserClaimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IdentityResource"); + + b.Navigation("UserClaim"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IdentityResource"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RolePermission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Permission") + .WithMany("RolePermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("Permissions") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Permission") + .WithMany("TeamPermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "Team") + .WithMany("TeamPermissions") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Permission") + .WithMany("UserPermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.Department", b => + { + b.Navigation("DepartmentStaffs"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Permission", b => + { + b.Navigation("AffiliationPermissionRelations"); + + b.Navigation("Children"); + + b.Navigation("LeadingPermissionRelations"); + + b.Navigation("RolePermissions"); + + b.Navigation("TeamPermissions"); + + b.Navigation("UserPermissions"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Role", b => + { + b.Navigation("ChildrenRoles"); + + b.Navigation("Clients"); + + b.Navigation("ParentRoles"); + + b.Navigation("Permissions"); + + b.Navigation("Teams"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Navigation("MessageTemplates"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => + { + b.Navigation("RegisterFields"); + + b.Navigation("ThirdPartyIdps"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", b => + { + b.Navigation("ThirdPartyUsers"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => + { + b.Navigation("DepartmentStaffs"); + + b.Navigation("TeamStaffs"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Team", b => + { + b.Navigation("TeamPermissions"); + + b.Navigation("TeamRoles"); + + b.Navigation("TeamStaffs"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.User", b => + { + b.Navigation("Permissions"); + + b.Navigation("Roles"); + + b.Navigation("Staff"); + + b.Navigation("SystemBusinessDatas"); + + b.Navigation("ThirdPartyUsers"); + + b.Navigation("UserClaims"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.Webhook", b => + { + b.Navigation("WebhookLogs"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", b => + { + b.Navigation("ApiScopes"); + + b.Navigation("Properties"); + + b.Navigation("Secrets"); + + b.Navigation("UserClaims"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", b => + { + b.Navigation("Properties"); + + b.Navigation("UserClaims"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", b => + { + b.Navigation("AllowedCorsOrigins"); + + b.Navigation("AllowedGrantTypes"); + + b.Navigation("AllowedScopes"); + + b.Navigation("Claims"); + + b.Navigation("ClientSecrets"); + + b.Navigation("IdentityProviderRestrictions"); + + b.Navigation("PostLogoutRedirectUris"); + + b.Navigation("Properties"); + + b.Navigation("RedirectUris"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", b => + { + b.Navigation("Properties"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/20260703082647_AddClientConfig.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/20260703082647_AddClientConfig.cs new file mode 100644 index 00000000..f8d928a1 --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/20260703082647_AddClientConfig.cs @@ -0,0 +1,130 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Masa.Auth.EntityFrameworkCore.PostgreSql.Migrations +{ + /// + public partial class AddClientConfig : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "_businessType", + schema: "auth", + table: "SubjectPermissionRelation", + type: "character varying(34)", + maxLength: 34, + nullable: false, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "Discriminator", + schema: "auth", + table: "IdentityProvider", + type: "character varying(21)", + maxLength: 21, + nullable: false, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.CreateTable( + name: "ClientConfig", + schema: "auth", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ClientId = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + PasswordRule = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + PasswordPrompt = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + PasswordRuleConfig = table.Column(type: "character varying(2000)", maxLength: 2000, nullable: true), + Creator = table.Column(type: "uuid", nullable: false), + CreationTime = table.Column(type: "timestamp with time zone", nullable: false), + Modifier = table.Column(type: "uuid", nullable: false), + ModificationTime = table.Column(type: "timestamp with time zone", nullable: false), + IsDeleted = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ClientConfig", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ClientMessageTemplate", + schema: "auth", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ClientConfigId = table.Column(type: "integer", nullable: false), + ChannelType = table.Column(type: "integer", nullable: false), + Scene = table.Column(type: "integer", nullable: false), + ChannelCode = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + TemplateCode = table.Column(type: "character varying(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ClientMessageTemplate", x => x.Id); + table.ForeignKey( + name: "FK_ClientMessageTemplate_ClientConfig_ClientConfigId", + column: x => x.ClientConfigId, + principalSchema: "auth", + principalTable: "ClientConfig", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ClientConfig_ClientId", + schema: "auth", + table: "ClientConfig", + column: "ClientId", + unique: true, + filter: "NOT \"IsDeleted\""); + + migrationBuilder.CreateIndex( + name: "IX_ClientMessageTemplate_ClientConfigId_ChannelType_Scene", + schema: "auth", + table: "ClientMessageTemplate", + columns: new[] { "ClientConfigId", "ChannelType", "Scene" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ClientMessageTemplate", + schema: "auth"); + + migrationBuilder.DropTable( + name: "ClientConfig", + schema: "auth"); + + migrationBuilder.AlterColumn( + name: "_businessType", + schema: "auth", + table: "SubjectPermissionRelation", + type: "text", + nullable: false, + oldClrType: typeof(string), + oldType: "character varying(34)", + oldMaxLength: 34); + + migrationBuilder.AlterColumn( + name: "Discriminator", + schema: "auth", + table: "IdentityProvider", + type: "text", + nullable: false, + oldClrType: typeof(string), + oldType: "character varying(21)", + oldMaxLength: 21); + } + } +} diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/AuthDbContextModelSnapshot.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/AuthDbContextModelSnapshot.cs index 80df8a76..6bb7617e 100644 --- a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/AuthDbContextModelSnapshot.cs +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.PostgreSql/Migrations/AuthDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasDefaultSchema("auth") - .HasAnnotation("ProductVersion", "6.0.36") + .HasAnnotation("ProductVersion", "10.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -573,13 +573,100 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("_businessType") .IsRequired() - .HasColumnType("text"); + .HasMaxLength(34) + .HasColumnType("character varying(34)"); b.HasKey("Id"); b.ToTable("SubjectPermissionRelation", "auth"); b.HasDiscriminator("_businessType").HasValue("SubjectPermissionRelation"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Creator") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("ModificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Modifier") + .HasColumnType("uuid"); + + b.Property("PasswordPrompt") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PasswordRule") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("PasswordRuleConfig") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("NOT \"IsDeleted\""); + + b.ToTable("ClientConfig", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ChannelType") + .HasColumnType("integer"); + + b.Property("ClientConfigId") + .HasColumnType("integer"); + + b.Property("Scene") + .HasColumnType("integer"); + + b.Property("TemplateCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientConfigId", "ChannelType", "Scene") + .IsUnique(); + + b.ToTable("ClientMessageTemplate", "auth"); }); modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => @@ -730,7 +817,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Discriminator") .IsRequired() - .HasColumnType("text"); + .HasMaxLength(21) + .HasColumnType("character varying(21)"); b.Property("DisplayName") .IsRequired() @@ -768,6 +856,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("IdentityProvider", "auth"); b.HasDiscriminator("Discriminator").HasValue("IdentityProvider"); + + b.UseTphMappingStrategy(); }); modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => @@ -2339,6 +2429,37 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("Role"); }); + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("TeamMemberType") + .HasColumnType("integer"); + + b.HasIndex("PermissionId"); + + b.HasIndex("TeamId"); + + b.HasDiscriminator().HasValue("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasIndex("PermissionId"); + + b.HasIndex("UserId"); + + b.HasDiscriminator().HasValue("User"); + }); + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.LdapIdp", b => { b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); @@ -2381,23 +2502,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("LDAP"); }); - modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => - { - b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); - - b.Property("TeamId") - .HasColumnType("uuid"); - - b.Property("TeamMemberType") - .HasColumnType("integer"); - - b.HasIndex("PermissionId"); - - b.HasIndex("TeamId"); - - b.HasDiscriminator().HasValue("Team"); - }); - modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyIdp", b => { b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); @@ -2441,20 +2545,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("ThirdParty"); }); - modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => - { - b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasIndex("PermissionId"); - - b.HasIndex("UserId"); - - b.HasDiscriminator().HasValue("User"); - }); - modelBuilder.Entity("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRole", b => { b.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ControlPolicy", "ControlPolicies", b1 => @@ -2682,6 +2772,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Role"); }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", null) + .WithMany("MessageTemplates") + .HasForeignKey("ClientConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => { b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "CreateUser") @@ -3268,6 +3367,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Users"); }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Navigation("MessageTemplates"); + }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => { b.Navigation("RegisterFields"); diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/EntityConfigurations/Sso/ClientConfigEntityTypeConfiguration.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/EntityConfigurations/Sso/ClientConfigEntityTypeConfiguration.cs new file mode 100644 index 00000000..2aeb3b48 --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/EntityConfigurations/Sso/ClientConfigEntityTypeConfiguration.cs @@ -0,0 +1,45 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +using System.Text.Json; +using Masa.BuildingBlocks.StackSdks.Mc.Enum; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace Masa.Auth.EntityFrameworkCore.SqlServer.EntityConfigurations.Sso; + +public class ClientConfigEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.ClientId).HasMaxLength(200).IsRequired(); + // Soft delete (IsDeleted) leaves the row in place, so the unique index must exclude + // deleted rows - otherwise a client can never be reconfigured after its config is removed. + builder.HasIndex(x => x.ClientId).IsUnique().HasFilter("[IsDeleted] = 0"); + builder.Property(x => x.PasswordRule).HasMaxLength(500); + builder.Property(x => x.PasswordPrompt).HasMaxLength(500); + builder.Property(x => x.PasswordRuleConfig) + .HasConversion( + v => v == null ? null : JsonSerializer.Serialize(v, (JsonSerializerOptions?)null), + v => string.IsNullOrWhiteSpace(v) + ? null + : JsonSerializer.Deserialize(v, (JsonSerializerOptions?)null)) + .Metadata.SetValueComparer(new ValueComparer( + (l, r) => JsonSerializer.Serialize(l, (JsonSerializerOptions?)null) == JsonSerializer.Serialize(r, (JsonSerializerOptions?)null), + v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null).GetHashCode(), + v => v == null ? null : v.Clone())); + builder.Property(x => x.PasswordRuleConfig).HasMaxLength(2000); + builder.HasMany(x => x.MessageTemplates).WithOne().HasForeignKey(x => x.ClientConfigId); + } +} + +public class ClientMessageTemplateEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.ChannelCode).HasMaxLength(200).IsRequired(); + builder.Property(x => x.TemplateCode).HasMaxLength(200).IsRequired(); + builder.HasIndex(x => new { x.ClientConfigId, x.ChannelType, x.Scene }).IsUnique(); + } +} \ No newline at end of file diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Masa.Auth.EntityFrameworkCore.SqlServer.csproj b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Masa.Auth.EntityFrameworkCore.SqlServer.csproj index 26f9202e..3506369a 100644 --- a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Masa.Auth.EntityFrameworkCore.SqlServer.csproj +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Masa.Auth.EntityFrameworkCore.SqlServer.csproj @@ -9,7 +9,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/20260703082754_AddClientConfig.Designer.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/20260703082754_AddClientConfig.Designer.cs new file mode 100644 index 00000000..19f81d90 --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/20260703082754_AddClientConfig.Designer.cs @@ -0,0 +1,3445 @@ +// +using System; +using Masa.Auth.Domain.Subjects.Aggregates; +using Masa.Auth.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Masa.Auth.Service.Admin.Migrations +{ + [DbContext(typeof(AuthDbContext))] + [Migration("20260703082754_AddClientConfig")] + partial class AddClientConfig + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("auth") + .HasAnnotation("ProductVersion", "10.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceFlowCodes", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("DynamicRole", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.GlobalNavs.Aggregates.GlobalNavVisible", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Visible") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("AppId"); + + b.HasIndex("ClientId"); + + b.ToTable("GlobalNavVisible", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Logs.Aggregates.OperationLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OperationDescription") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("OperationTime") + .HasColumnType("datetime2"); + + b.Property("OperationType") + .HasColumnType("int"); + + b.Property("Operator") + .HasColumnType("uniqueidentifier"); + + b.Property("OperatorName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("OperationDescription"); + + b.HasIndex("OperationTime"); + + b.HasIndex("OperationType"); + + b.HasIndex("Operator"); + + b.ToTable("OperationLog", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.Department", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Level") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Sort") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Level"); + + b.HasIndex("Name", "ParentId"); + + b.ToTable("Department", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.DepartmentStaff", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("DepartmentId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("StaffId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("DepartmentId"); + + b.HasIndex("StaffId"); + + b.ToTable("DepartmentStaff", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.Position", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Position", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("Icon") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Legend") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MatchPattern") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("SystemId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("SystemId", "AppId", "Code"); + + b.ToTable("Permission", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.PermissionRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AffiliationPermissionId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LeadingPermissionId") + .HasColumnType("uniqueidentifier"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("AffiliationPermissionId"); + + b.HasIndex("LeadingPermissionId", "AffiliationPermissionId"); + + b.ToTable("PermissionRelation", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AvailableQuantity") + .HasColumnType("int"); + + b.Property("Code") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Limit") + .HasColumnType("int"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(2); + + b.HasKey("Id"); + + b.ToTable("Role", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleClient", b => + { + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("RoleId", "ClientId"); + + b.ToTable("RoleClient", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleRelation", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Effect") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("PermissionId") + .HasColumnType("uniqueidentifier"); + + b.Property("_businessType") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("nvarchar(34)"); + + b.HasKey("Id"); + + b.ToTable("SubjectPermissionRelation", "auth"); + + b.HasDiscriminator("_businessType").HasValue("SubjectPermissionRelation"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("PasswordPrompt") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("PasswordRule") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("PasswordRuleConfig") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); + + b.ToTable("ClientConfig", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChannelCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ChannelType") + .HasColumnType("int"); + + b.Property("ClientConfigId") + .HasColumnType("int"); + + b.Property("Scene") + .HasColumnType("int"); + + b.Property("TemplateCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientConfigId", "ChannelType", "Scene") + .IsUnique(); + + b.ToTable("ClientMessageTemplate", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Creator"); + + b.HasIndex("Modifier"); + + b.HasIndex("Name"); + + b.ToTable("CustomLogin", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLoginThirdPartyIdp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomLoginId") + .HasColumnType("int"); + + b.Property("Sort") + .HasColumnType("int"); + + b.Property("ThirdPartyIdpId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("CustomLoginId"); + + b.HasIndex("ThirdPartyIdpId"); + + b.ToTable("CustomLoginThirdPartyIdp", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.RegisterField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CustomLoginId") + .HasColumnType("int"); + + b.Property("RegisterFieldType") + .HasColumnType("int"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("Sort") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CustomLoginId"); + + b.ToTable("RegisterField", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("nvarchar(21)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("Icon") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("ThirdPartyIdpType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("IdentityProvider", "auth"); + + b.HasDiscriminator("Discriminator").HasValue("IdentityProvider"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Avatar") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("CurrentTeamId") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("Gender") + .HasColumnType("int"); + + b.Property("IdCard") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("JobNumber") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PositionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StaffType") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("CurrentTeamId"); + + b.HasIndex("JobNumber"); + + b.HasIndex("PositionId"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Staff", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("TeamType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Team", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TeamId") + .HasColumnType("uniqueidentifier"); + + b.Property("TeamMemberType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamRole", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamStaff", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("StaffId") + .HasColumnType("uniqueidentifier"); + + b.Property("TeamId") + .HasColumnType("uniqueidentifier"); + + b.Property("TeamMemberType") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("StaffId"); + + b.HasIndex("TeamId"); + + b.ToTable("TeamStaff", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("ExtendedData") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IdentityProviderId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("ThirdPartyIdpId") + .HasColumnType("uniqueidentifier"); + + b.Property("ThridPartyIdentity") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("IdentityProviderId"); + + b.HasIndex("ThirdPartyIdpId"); + + b.HasIndex("UserId"); + + b.HasIndex("CreationTime", "ModificationTime"); + + b.ToTable("ThirdPartyUser", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Account") + .IsRequired() + .HasColumnType("nvarchar(450)") + .UseCollation("SQL_Latin1_General_CP1_CS_AS"); + + b.Property("Avatar") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasDefaultValue(""); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Department") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("Gender") + .HasColumnType("int"); + + b.Property("IdCard") + .IsRequired() + .HasMaxLength(18) + .HasColumnType("nvarchar(18)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("Landline") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Password") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PasswordType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(11) + .HasColumnType("nvarchar(11)"); + + b.Property("Position") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Account"); + + b.HasIndex("ClientId"); + + b.HasIndex("Email"); + + b.HasIndex("IdCard"); + + b.HasIndex("Name"); + + b.HasIndex("PhoneNumber"); + + b.HasIndex("CreationTime", "ModificationTime"); + + b.ToTable("User", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserClaimValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaimValue", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.ToTable("UserRole", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserSystemBusinessData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("SystemId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "SystemId"); + + b.ToTable("UserSystemBusinessData", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Event") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("HttpMethod") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Secret") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Webhook", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.WebhookLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WebhookId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookLog", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AllowedAccessTokenSigningAlgorithms") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("NonEditable") + .HasColumnType("bit"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); + + b.ToTable("ApiResource", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApiResourceId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("UserClaimId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.HasIndex("UserClaimId"); + + b.ToTable("ApiResourceClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApiResourceId") + .HasColumnType("uniqueidentifier"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApiResourceId") + .HasColumnType("uniqueidentifier"); + + b.Property("ApiScopeId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.HasIndex("ApiScopeId"); + + b.ToTable("ApiResourceScope", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApiResourceId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.HasKey("Id"); + + b.HasIndex("ApiResourceId"); + + b.ToTable("ApiResourceSecret", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Emphasize") + .HasColumnType("bit"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ApiScope", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApiScopeId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("UserClaimId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ApiScopeId"); + + b.HasIndex("UserClaimId"); + + b.ToTable("ApiScopeClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("ScopeId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ScopeId"); + + b.ToTable("ApiScopeProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenType") + .HasColumnType("int"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("bit"); + + b.Property("AllowOfflineAccess") + .HasColumnType("bit"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("bit"); + + b.Property("AllowRememberConsent") + .HasColumnType("bit"); + + b.Property("AllowedIdentityTokenSigningAlgorithms") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("bit"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("bit"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("int"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("bit"); + + b.Property("BackChannelLogoutUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ClientClaimsPrefix") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientType") + .HasColumnType("int"); + + b.Property("ClientUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ConsentLifetime") + .HasColumnType("int"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DeviceCodeLifetime") + .HasColumnType("int"); + + b.Property("EnableLocalLogin") + .HasColumnType("bit"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("bit"); + + b.Property("FrontChannelLogoutUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("IdentityTokenLifetime") + .HasColumnType("int"); + + b.Property("IncludeJwtId") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("LogoUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("NonEditable") + .HasColumnType("bit"); + + b.Property("PairWiseSubjectSalt") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ProtocolType") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("RefreshTokenExpiration") + .HasColumnType("int"); + + b.Property("RefreshTokenUsage") + .HasColumnType("int"); + + b.Property("RequireClientSecret") + .HasColumnType("bit"); + + b.Property("RequireConsent") + .HasColumnType("bit"); + + b.Property("RequirePkce") + .HasColumnType("bit"); + + b.Property("RequireRequestObject") + .HasColumnType("bit"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("bit"); + + b.Property("UserCodeType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("UserSsoLifetime") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); + + b.ToTable("Client", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientCorsOrigin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("Origin") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientCorsOrigin", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientGrantType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("GrantType") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientGrantType", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientIdPRestriction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientIdPRestriction", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientPostLogoutRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("PostLogoutRedirectUri") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientPostLogoutRedirectUri", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientRedirectUri", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("RedirectUri") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientRedirectUri", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("Scope") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientScope", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientSecret", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ClientSecret", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Emphasize") + .HasColumnType("bit"); + + b.Property("Enabled") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("NonEditable") + .HasColumnType("bit"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); + + b.ToTable("IdentityResource", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IdentityResourceId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("UserClaimId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.HasIndex("UserClaimId"); + + b.ToTable("IdentityResourceClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceProperty", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("IdentityResourceId") + .HasColumnType("uniqueidentifier"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("IdentityResourceId"); + + b.ToTable("IdentityResourceProperty", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("UserClaim", "auth"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Dispatcher.IntegrationEvents.Logs.IntegrationEventLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("EventId") + .HasColumnType("uniqueidentifier"); + + b.Property("EventTypeName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExpandContent") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(36) + .HasColumnType("nvarchar(36)") + .HasColumnName("RowVersion"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("TimesSent") + .HasColumnType("int"); + + b.Property("TransactionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex(new[] { "EventId", "RowVersion" }, "IX_EventId_Version"); + + b.HasIndex(new[] { "State", "ModificationTime" }, "IX_State_MTime"); + + b.HasIndex(new[] { "State", "TimesSent", "ModificationTime" }, "IX_State_TimesSent_MTime"); + + b.ToTable("IntegrationEventLog", "auth"); + }); + + modelBuilder.Entity("PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrant", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RolePermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasIndex("PermissionId"); + + b.HasIndex("RoleId"); + + b.HasDiscriminator().HasValue("Role"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("TeamId") + .HasColumnType("uniqueidentifier"); + + b.Property("TeamMemberType") + .HasColumnType("int"); + + b.HasIndex("PermissionId"); + + b.HasIndex("TeamId"); + + b.HasDiscriminator().HasValue("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasIndex("PermissionId"); + + b.HasIndex("UserId"); + + b.HasDiscriminator().HasValue("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.LdapIdp", b => + { + b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); + + b.Property("BaseDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("GroupSearchBaseDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsSSL") + .HasColumnType("bit"); + + b.Property("RootUserDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("RootUserPassword") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ServerAddress") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ServerPort") + .HasColumnType("int"); + + b.Property("UserSearchBaseDn") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasDiscriminator().HasValue("LDAP"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyIdp", b => + { + b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); + + b.Property("AuthenticationType") + .HasColumnType("int"); + + b.Property("AuthorizationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CallbackPath") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ClientSecret") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("JsonKeyMap") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MapAll") + .HasColumnType("bit"); + + b.Property("TokenEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UserInformationEndpoint") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasDiscriminator().HasValue("ThirdParty"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRole", b => + { + b.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ControlPolicy", "ControlPolicies", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b1.Property("DynamicRoleId") + .HasColumnType("uniqueidentifier"); + + b1.Property("Effect") + .HasColumnType("int"); + + b1.Property("Enabled") + .HasColumnType("bit"); + + b1.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b1.Property("Priority") + .HasColumnType("int"); + + b1.HasKey("Id"); + + b1.HasIndex("DynamicRoleId"); + + b1.ToTable("ControlPolicy", "auth"); + + b1.WithOwner() + .HasForeignKey("DynamicRoleId"); + + b1.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ActionIdentifier", "Actions", b2 => + { + b2.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b2.Property("ControlPolicyId") + .HasColumnType("uniqueidentifier"); + + b2.Property("Operation") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b2.Property("Resource") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b2.Property("Type") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b2.HasKey("Id"); + + b2.HasIndex("ControlPolicyId"); + + b2.ToTable("ActionIdentifier", "auth"); + + b2.WithOwner() + .HasForeignKey("ControlPolicyId"); + }); + + b1.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ResourceIdentifier", "Resources", b2 => + { + b2.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b2.Property("ControlPolicyId") + .HasColumnType("uniqueidentifier"); + + b2.Property("Identifier") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b2.Property("Region") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b2.Property("Service") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b2.HasKey("Id"); + + b2.HasIndex("ControlPolicyId"); + + b2.ToTable("ResourceIdentifier", "auth"); + + b2.WithOwner() + .HasForeignKey("ControlPolicyId"); + }); + + b1.Navigation("Actions"); + + b1.Navigation("Resources"); + }); + + b.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRuleCondition", "Conditions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b1.Property("DataType") + .HasColumnType("int"); + + b1.Property("DynamicRoleId") + .HasColumnType("uniqueidentifier"); + + b1.Property("FieldName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b1.Property("LogicalOperator") + .HasColumnType("int"); + + b1.Property("OperatorType") + .HasColumnType("int"); + + b1.Property("Order") + .HasColumnType("int"); + + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.HasKey("Id"); + + b1.HasIndex("DynamicRoleId"); + + b1.ToTable("DynamicRuleCondition", "auth"); + + b1.WithOwner() + .HasForeignKey("DynamicRoleId"); + }); + + b.Navigation("Conditions"); + + b.Navigation("ControlPolicies"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.DepartmentStaff", b => + { + b.HasOne("Masa.Auth.Domain.Organizations.Aggregates.Department", "Department") + .WithMany("DepartmentStaffs") + .HasForeignKey("DepartmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Staff", "Staff") + .WithMany("DepartmentStaffs") + .HasForeignKey("StaffId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Department"); + + b.Navigation("Staff"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Permission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.PermissionRelation", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "AffiliationPermission") + .WithMany("LeadingPermissionRelations") + .HasForeignKey("AffiliationPermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "LeadingPermission") + .WithMany("AffiliationPermissionRelations") + .HasForeignKey("LeadingPermissionId") + .OnDelete(DeleteBehavior.ClientCascade) + .IsRequired(); + + b.Navigation("AffiliationPermission"); + + b.Navigation("LeadingPermission"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleClient", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", null) + .WithMany("Clients") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RoleRelation", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "ParentRole") + .WithMany("ChildrenRoles") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("ParentRoles") + .HasForeignKey("RoleId") + .IsRequired(); + + b.Navigation("ParentRole"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", null) + .WithMany("MessageTemplates") + .HasForeignKey("ClientConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "CreateUser") + .WithMany() + .HasForeignKey("Creator"); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "ModifyUser") + .WithMany() + .HasForeignKey("Modifier"); + + b.Navigation("CreateUser"); + + b.Navigation("ModifyUser"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLoginThirdPartyIdp", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", null) + .WithMany("ThirdPartyIdps") + .HasForeignKey("CustomLoginId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyIdp", "ThirdPartyIdp") + .WithMany() + .HasForeignKey("ThirdPartyIdpId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ThirdPartyIdp"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.RegisterField", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", null) + .WithMany("RegisterFields") + .HasForeignKey("CustomLoginId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "CurrentTeam") + .WithMany() + .HasForeignKey("CurrentTeamId"); + + b.HasOne("Masa.Auth.Domain.Organizations.Aggregates.Position", "Position") + .WithMany() + .HasForeignKey("PositionId"); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithOne("Staff") + .HasForeignKey("Masa.Auth.Domain.Subjects.Aggregates.Staff", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Masa.Auth.Domain.Subjects.Aggregates.AddressValue", "Address", b1 => + { + b1.Property("StaffId") + .HasColumnType("uniqueidentifier"); + + b1.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("CityCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("DistrictCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("ProvinceCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.HasKey("StaffId"); + + b1.ToTable("Staff", "auth"); + + b1.WithOwner() + .HasForeignKey("StaffId"); + }); + + b.Navigation("Address") + .IsRequired(); + + b.Navigation("CurrentTeam"); + + b.Navigation("Position"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Team", b => + { + b.OwnsOne("Masa.Auth.Domain.Subjects.Aggregates.AvatarValue", "Avatar", b1 => + { + b1.Property("TeamId") + .HasColumnType("uniqueidentifier"); + + b1.Property("Color") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.HasKey("TeamId"); + + b1.ToTable("Team", "auth"); + + b1.WithOwner() + .HasForeignKey("TeamId"); + }); + + b.Navigation("Avatar") + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamRole", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("Teams") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "Team") + .WithMany("TeamRoles") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamStaff", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Staff", "Staff") + .WithMany("TeamStaffs") + .HasForeignKey("StaffId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "Team") + .WithMany("TeamStaffs") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Staff"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyUser", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", null) + .WithMany("ThirdPartyUsers") + .HasForeignKey("IdentityProviderId"); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", "IdentityProvider") + .WithMany() + .HasForeignKey("ThirdPartyIdpId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("ThirdPartyUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IdentityProvider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.User", b => + { + b.OwnsOne("Masa.Auth.Domain.Subjects.Aggregates.AddressValue", "Address", b1 => + { + b1.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b1.Property("Address") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("CityCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("DistrictCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.Property("ProvinceCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b1.HasKey("UserId"); + + b1.ToTable("User", "auth"); + + b1.WithOwner() + .HasForeignKey("UserId"); + }); + + b.Navigation("Address") + .IsRequired(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserClaimValue", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("UserClaims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserRole", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("Users") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserSystemBusinessData", b => + { + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("SystemBusinessDatas") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.WebhookLog", b => + { + b.HasOne("Masa.Auth.Domain.Webhooks.Aggregates.Webhook", "Webhook") + .WithMany("WebhookLogs") + .HasForeignKey("WebhookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Webhook"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", "UserClaim") + .WithMany() + .HasForeignKey("UserClaimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + + b.Navigation("UserClaim"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("Properties") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceScope", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("ApiScopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", "ApiScope") + .WithMany() + .HasForeignKey("ApiScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + + b.Navigation("ApiScope"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResourceSecret", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", "ApiResource") + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiResource"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", "ApiScope") + .WithMany("UserClaims") + .HasForeignKey("ApiScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", "UserClaim") + .WithMany() + .HasForeignKey("UserClaimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApiScope"); + + b.Navigation("UserClaim"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScopeProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", "Scope") + .WithMany("Properties") + .HasForeignKey("ScopeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Scope"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientCorsOrigin", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientGrantType", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientIdPRestriction", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientRedirectUri", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientScope", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ClientSecret", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", "Client") + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Client"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceClaim", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", "IdentityResource") + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.UserClaim", "UserClaim") + .WithMany() + .HasForeignKey("UserClaimId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IdentityResource"); + + b.Navigation("UserClaim"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResourceProperty", b => + { + b.HasOne("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", "IdentityResource") + .WithMany("Properties") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IdentityResource"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.RolePermission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Permission") + .WithMany("RolePermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Role", "Role") + .WithMany("Permissions") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Permission") + .WithMany("TeamPermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.Team", "Team") + .WithMany("TeamPermissions") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => + { + b.HasOne("Masa.Auth.Domain.Permissions.Aggregates.Permission", "Permission") + .WithMany("UserPermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "User") + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Permission"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Organizations.Aggregates.Department", b => + { + b.Navigation("DepartmentStaffs"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Permission", b => + { + b.Navigation("AffiliationPermissionRelations"); + + b.Navigation("Children"); + + b.Navigation("LeadingPermissionRelations"); + + b.Navigation("RolePermissions"); + + b.Navigation("TeamPermissions"); + + b.Navigation("UserPermissions"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Permissions.Aggregates.Role", b => + { + b.Navigation("ChildrenRoles"); + + b.Navigation("Clients"); + + b.Navigation("ParentRoles"); + + b.Navigation("Permissions"); + + b.Navigation("Teams"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Navigation("MessageTemplates"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => + { + b.Navigation("RegisterFields"); + + b.Navigation("ThirdPartyIdps"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider", b => + { + b.Navigation("ThirdPartyUsers"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => + { + b.Navigation("DepartmentStaffs"); + + b.Navigation("TeamStaffs"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Team", b => + { + b.Navigation("TeamPermissions"); + + b.Navigation("TeamRoles"); + + b.Navigation("TeamStaffs"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.User", b => + { + b.Navigation("Permissions"); + + b.Navigation("Roles"); + + b.Navigation("Staff"); + + b.Navigation("SystemBusinessDatas"); + + b.Navigation("ThirdPartyUsers"); + + b.Navigation("UserClaims"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Webhooks.Aggregates.Webhook", b => + { + b.Navigation("WebhookLogs"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiResource", b => + { + b.Navigation("ApiScopes"); + + b.Navigation("Properties"); + + b.Navigation("Secrets"); + + b.Navigation("UserClaims"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.ApiScope", b => + { + b.Navigation("Properties"); + + b.Navigation("UserClaims"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.Client", b => + { + b.Navigation("AllowedCorsOrigins"); + + b.Navigation("AllowedGrantTypes"); + + b.Navigation("AllowedScopes"); + + b.Navigation("Claims"); + + b.Navigation("ClientSecrets"); + + b.Navigation("IdentityProviderRestrictions"); + + b.Navigation("PostLogoutRedirectUris"); + + b.Navigation("Properties"); + + b.Navigation("RedirectUris"); + }); + + modelBuilder.Entity("Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain.Entities.IdentityResource", b => + { + b.Navigation("Properties"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/20260703082754_AddClientConfig.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/20260703082754_AddClientConfig.cs new file mode 100644 index 00000000..fb9b2588 --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/20260703082754_AddClientConfig.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Masa.Auth.Service.Admin.Migrations +{ + /// + public partial class AddClientConfig : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/AuthDbContextModelSnapshot.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/AuthDbContextModelSnapshot.cs index 86dc2f13..a771dd00 100644 --- a/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/AuthDbContextModelSnapshot.cs +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore.SqlServer/Migrations/AuthDbContextModelSnapshot.cs @@ -19,10 +19,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasDefaultSchema("auth") - .HasAnnotation("ProductVersion", "6.0.36") + .HasAnnotation("ProductVersion", "10.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 128); - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("DeviceFlowCodes", b => { @@ -52,8 +52,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(200) .HasColumnType("nvarchar(200)"); - b.Property("Expiration") - .IsRequired() + b.Property("Expiration") .HasColumnType("datetime2"); b.Property("SessionId") @@ -575,13 +574,100 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("_businessType") .IsRequired() - .HasColumnType("nvarchar(max)"); + .HasMaxLength(34) + .HasColumnType("nvarchar(34)"); b.HasKey("Id"); b.ToTable("SubjectPermissionRelation", "auth"); b.HasDiscriminator("_businessType").HasValue("SubjectPermissionRelation"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Creator") + .HasColumnType("uniqueidentifier"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("ModificationTime") + .HasColumnType("datetime2"); + + b.Property("Modifier") + .HasColumnType("uniqueidentifier"); + + b.Property("PasswordPrompt") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("PasswordRule") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("PasswordRuleConfig") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); + + b.ToTable("ClientConfig", "auth"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChannelCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ChannelType") + .HasColumnType("int"); + + b.Property("ClientConfigId") + .HasColumnType("int"); + + b.Property("Scene") + .HasColumnType("int"); + + b.Property("TemplateCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("ClientConfigId", "ChannelType", "Scene") + .IsUnique(); + + b.ToTable("ClientMessageTemplate", "auth"); }); modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => @@ -590,7 +676,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("ClientId") .IsRequired() @@ -640,7 +726,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("CustomLoginId") .HasColumnType("int"); @@ -666,7 +752,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("CustomLoginId") .HasColumnType("int"); @@ -701,7 +787,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Discriminator") .IsRequired() - .HasColumnType("nvarchar(max)"); + .HasMaxLength(21) + .HasColumnType("nvarchar(21)"); b.Property("DisplayName") .IsRequired() @@ -739,6 +826,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("IdentityProvider", "auth"); b.HasDiscriminator("Discriminator").HasValue("IdentityProvider"); + + b.UseTphMappingStrategy(); }); modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.Staff", b => @@ -2311,6 +2400,37 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("Role"); }); + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("TeamId") + .HasColumnType("uniqueidentifier"); + + b.Property("TeamMemberType") + .HasColumnType("int"); + + b.HasIndex("PermissionId"); + + b.HasIndex("TeamId"); + + b.HasDiscriminator().HasValue("Team"); + }); + + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => + { + b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasIndex("PermissionId"); + + b.HasIndex("UserId"); + + b.HasDiscriminator().HasValue("User"); + }); + modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.LdapIdp", b => { b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); @@ -2353,23 +2473,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("LDAP"); }); - modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.TeamPermission", b => - { - b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); - - b.Property("TeamId") - .HasColumnType("uniqueidentifier"); - - b.Property("TeamMemberType") - .HasColumnType("int"); - - b.HasIndex("PermissionId"); - - b.HasIndex("TeamId"); - - b.HasDiscriminator().HasValue("Team"); - }); - modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.ThirdPartyIdp", b => { b.HasBaseType("Masa.Auth.Domain.Subjects.Aggregates.IdentityProvider"); @@ -2413,20 +2516,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("ThirdParty"); }); - modelBuilder.Entity("Masa.Auth.Domain.Subjects.Aggregates.UserPermission", b => - { - b.HasBaseType("Masa.Auth.Domain.Permissions.Aggregates.SubjectPermissionRelation"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier"); - - b.HasIndex("PermissionId"); - - b.HasIndex("UserId"); - - b.HasDiscriminator().HasValue("User"); - }); - modelBuilder.Entity("Masa.Auth.Domain.DynamicRoles.Aggregates.DynamicRole", b => { b.OwnsMany("Masa.Auth.Domain.DynamicRoles.Aggregates.ControlPolicy", "ControlPolicies", b1 => @@ -2654,6 +2743,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Role"); }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientMessageTemplate", b => + { + b.HasOne("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", null) + .WithMany("MessageTemplates") + .HasForeignKey("ClientConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => { b.HasOne("Masa.Auth.Domain.Subjects.Aggregates.User", "CreateUser") @@ -3240,6 +3338,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Users"); }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.ClientConfig", b => + { + b.Navigation("MessageTemplates"); + }); + modelBuilder.Entity("Masa.Auth.Domain.Sso.Aggregates.CustomLogin", b => { b.Navigation("RegisterFields"); diff --git a/src/Infrastructure/Masa.Auth.EntityFrameworkCore/Repositories/ClientConfigRepository.cs b/src/Infrastructure/Masa.Auth.EntityFrameworkCore/Repositories/ClientConfigRepository.cs new file mode 100644 index 00000000..33c0238b --- /dev/null +++ b/src/Infrastructure/Masa.Auth.EntityFrameworkCore/Repositories/ClientConfigRepository.cs @@ -0,0 +1,19 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.EntityFrameworkCore.Repositories; + +public class ClientConfigRepository : Repository, IClientConfigRepository +{ + public ClientConfigRepository(AuthDbContext context, IUnitOfWork unitOfWork) : base(context, unitOfWork) + { + } + + public async Task FindByClientIdAsync(string clientId) + { + return await Context.Set() + .Include(x => x.MessageTemplates) + .AsTracking() + .FirstOrDefaultAsync(x => x.ClientId == clientId); + } +} diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Messages/CommandHandler.cs b/src/Services/Masa.Auth.Service.Admin/Application/Messages/CommandHandler.cs index dcdfbca0..c60dc472 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Messages/CommandHandler.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Messages/CommandHandler.cs @@ -69,7 +69,7 @@ public async Task SendSmsAsync(SendSmsCommand command) } else { - await _sms.SendMsgCodeAsync(cacheKey, model.PhoneNumber); + await _sms.SendMsgCodeAsync(cacheKey, model.PhoneNumber, model.ClientId, model.SendMsgCodeType); } } @@ -99,7 +99,7 @@ public async Task SendEmailAsync(SendEmailCommand command) default: throw new UserFriendlyException(errorCode: UserFriendlyExceptionCodes.INVALID_SEND_EMAIL_TYPE); } - await _emailAgent.SendEmailAsync(model); + await _emailAgent.SendEmailAsync(model, model.ClientId); } async Task CheckUserExistAsync(Guid userId) diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Sso/ClientPasswordRuleRegexConverter.cs b/src/Services/Masa.Auth.Service.Admin/Application/Sso/ClientPasswordRuleRegexConverter.cs new file mode 100644 index 00000000..7dff3455 --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Application/Sso/ClientPasswordRuleRegexConverter.cs @@ -0,0 +1,181 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Service.Admin.Application.Sso; + +internal static class ClientPasswordRuleRegexConverter +{ + private static readonly Regex ConfigRuleRegex = new( + @"^\^\(\?=\\S\{(?\d+),(?\d+)\}\$\)(?(?:\(\?=\\S\*\[A-Z\]\)|\(\?=\\S\*\[a-z\]\)|\(\?=\\S\*\\d\)|\(\?=\\S\*\[\^A-Za-z0-9\\s\]\))*)\\S\*\$$", + RegexOptions.Compiled); + + public static ClientPasswordRuleDto Normalize(ClientPasswordRuleDto? passwordRule) + { + if (passwordRule is null) + { + passwordRule = new(); + } + + passwordRule.MinLength = Math.Max(1, passwordRule.MinLength); + passwordRule.MaxLength = Math.Max(passwordRule.MinLength, passwordRule.MaxLength); + passwordRule.RegexPattern = passwordRule.RegexPattern?.Trim() ?? string.Empty; + + if (string.IsNullOrWhiteSpace(passwordRule.PasswordPrompt)) + { + passwordRule.PasswordPrompt = BuildPasswordPrompt(passwordRule); + } + else + { + passwordRule.PasswordPrompt = passwordRule.PasswordPrompt.Trim(); + } + + return passwordRule; + } + + public static string? ToRegex(ClientPasswordRuleDto? passwordRule) + { + passwordRule = Normalize(passwordRule); + + if (passwordRule.UseRegexPattern) + { + return string.IsNullOrEmpty(passwordRule.RegexPattern) + ? null + : passwordRule.RegexPattern; + } + + var minLength = Math.Max(1, passwordRule.MinLength); + var maxLength = Math.Max(minLength, passwordRule.MaxLength); + var lookaheads = new List(); + + if (passwordRule.RequireUppercase) + { + lookaheads.Add(@"(?=\S*[A-Z])"); + } + + if (passwordRule.RequireLowercase) + { + lookaheads.Add(@"(?=\S*[a-z])"); + } + + if (passwordRule.RequireDigit) + { + lookaheads.Add(@"(?=\S*\d)"); + } + + if (passwordRule.RequireSpecialCharacter) + { + lookaheads.Add(@"(?=\S*[^A-Za-z0-9\s])"); + } + + return $@"^(?=\S{{{minLength},{maxLength}}}$){string.Join(string.Empty, lookaheads)}\S*$"; + } + + public static ClientPasswordRuleConfig ToDomainConfig(ClientPasswordRuleDto? passwordRule) + { + passwordRule = Normalize(passwordRule); + + return new ClientPasswordRuleConfig + { + MinLength = passwordRule.MinLength, + MaxLength = passwordRule.MaxLength, + RequireUppercase = passwordRule.RequireUppercase, + RequireLowercase = passwordRule.RequireLowercase, + RequireDigit = passwordRule.RequireDigit, + RequireSpecialCharacter = passwordRule.RequireSpecialCharacter, + UseRegexPattern = passwordRule.UseRegexPattern, + RegexPattern = passwordRule.RegexPattern, + PasswordPrompt = passwordRule.PasswordPrompt + }; + } + + public static ClientPasswordRuleDto FromStorage(ClientPasswordRuleConfig? passwordRuleConfig, string? regexPattern, string? passwordPrompt) + { + if (passwordRuleConfig is not null) + { + return Normalize(new ClientPasswordRuleDto + { + MinLength = passwordRuleConfig.MinLength, + MaxLength = passwordRuleConfig.MaxLength, + RequireUppercase = passwordRuleConfig.RequireUppercase, + RequireLowercase = passwordRuleConfig.RequireLowercase, + RequireDigit = passwordRuleConfig.RequireDigit, + RequireSpecialCharacter = passwordRuleConfig.RequireSpecialCharacter, + UseRegexPattern = passwordRuleConfig.UseRegexPattern, + RegexPattern = passwordRuleConfig.RegexPattern, + PasswordPrompt = string.IsNullOrWhiteSpace(passwordRuleConfig.PasswordPrompt) + ? passwordPrompt + : passwordRuleConfig.PasswordPrompt + }); + } + + var legacyPasswordRule = FromRegex(regexPattern); + legacyPasswordRule.PasswordPrompt = string.IsNullOrWhiteSpace(passwordPrompt) + ? legacyPasswordRule.PasswordPrompt + : passwordPrompt; + return Normalize(legacyPasswordRule); + } + + private static ClientPasswordRuleDto FromRegex(string? regexPattern) + { + if (string.IsNullOrWhiteSpace(regexPattern)) + { + return new(); + } + + var match = ConfigRuleRegex.Match(regexPattern); + if (!match.Success) + { + return new ClientPasswordRuleDto + { + UseRegexPattern = true, + RegexPattern = regexPattern + }; + } + + var checks = match.Groups["checks"].Value; + return new ClientPasswordRuleDto + { + MinLength = int.Parse(match.Groups["min"].Value), + MaxLength = int.Parse(match.Groups["max"].Value), + RequireUppercase = checks.Contains(@"(?=\S*[A-Z])"), + RequireLowercase = checks.Contains(@"(?=\S*[a-z])"), + RequireDigit = checks.Contains(@"(?=\S*\d)"), + RequireSpecialCharacter = checks.Contains(@"(?=\S*[^A-Za-z0-9\s])") + }; + } + + private static string BuildPasswordPrompt(ClientPasswordRuleDto passwordRule) + { + if (passwordRule.UseRegexPattern) + { + return "PasswordValidateFailed"; + } + + var requirements = new List + { + $"Password length must be between {passwordRule.MinLength} and {passwordRule.MaxLength} characters" + }; + + if (passwordRule.RequireUppercase) + { + requirements.Add("include an uppercase letter"); + } + + if (passwordRule.RequireLowercase) + { + requirements.Add("include a lowercase letter"); + } + + if (passwordRule.RequireDigit) + { + requirements.Add("include a digit"); + } + + if (passwordRule.RequireSpecialCharacter) + { + requirements.Add("include a special character"); + } + + return string.Join(", ", requirements); + } +} \ No newline at end of file diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Sso/CommandHandler.cs b/src/Services/Masa.Auth.Service.Admin/Application/Sso/CommandHandler.cs index 178dd5f9..4fc0b721 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Sso/CommandHandler.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Sso/CommandHandler.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the Apache License. See LICENSE.txt in the project root for license information. namespace Masa.Auth.Service.Admin.Application.Sso; @@ -12,6 +12,7 @@ public class CommandHandler readonly IUserClaimRepository _userClaimRepository; readonly ICustomLoginRepository _customLoginRepository; readonly IUserClaimExtendRepository _userClaimExtendRepository; + readonly IClientConfigRepository _clientConfigRepository; readonly IEventBus _eventBus; readonly SyncCache _syncCache; @@ -23,6 +24,7 @@ public CommandHandler( IUserClaimRepository userClaimRepository, ICustomLoginRepository customLoginRepository, IUserClaimExtendRepository userClaimExtendRepository, + IClientConfigRepository clientConfigRepository, IEventBus eventBus, SyncCache syncCache) { @@ -33,6 +35,7 @@ public CommandHandler( _userClaimRepository = userClaimRepository; _customLoginRepository = customLoginRepository; _userClaimExtendRepository = userClaimExtendRepository; + _clientConfigRepository = clientConfigRepository; _eventBus = eventBus; _syncCache = syncCache; } @@ -41,8 +44,9 @@ public CommandHandler( [EventHandler] public async Task AddClientAsync(AddClientCommand addClientCommand) { - var client = addClientCommand.AddClientDto.Adapt(); - client.SetClientType(addClientCommand.AddClientDto.ClientType); + var dto = addClientCommand.AddClientDto; + var client = dto.Adapt(); + client.SetClientType(dto.ClientType); await ValidateClientIdAsync(client.ClientId); await _clientRepository.AddAsync(client); } @@ -50,8 +54,9 @@ public async Task AddClientAsync(AddClientCommand addClientCommand) [EventHandler] public async Task UpdateClientAsync(UpdateClientCommand updateClientCommand) { - var id = updateClientCommand.ClientDetailDto.Id; - updateClientCommand.ClientDetailDto.ClientSecrets.ForEach(secret => + var dto = updateClientCommand.ClientDetailDto; + var id = dto.Id; + dto.ClientSecrets.ForEach(secret => { HashClientSharedSecret(secret); }); @@ -59,11 +64,12 @@ public async Task UpdateClientAsync(UpdateClientCommand updateClientCommand) var client = await _clientRepository.GetDetailAsync(id) ?? throw new UserFriendlyException(errorCode: UserFriendlyExceptionCodes.CLIENT_NOT_EXIST); //Contrary to DDD - updateClientCommand.ClientDetailDto.Adapt(client); + dto.Adapt(client); await ValidateClientIdAsync(client.ClientId, client.Id); await _clientRepository.UpdateAsync(client); + await UpsertClientConfigAsync(client.ClientId, dto.PasswordRule, dto.SmsTemplates, dto.EmailTemplates); void HashClientSharedSecret(ClientSecretDto clientSecret) { if (clientSecret.Id != Guid.Empty) @@ -107,6 +113,50 @@ private async Task ValidateClientIdAsync(string clientId, Guid? id = null) } } + [EventHandler] + public async Task UpsertClientConfigAsync(UpsertClientConfigCommand command) + { + var dto = command.ClientConfig; + ArgumentExceptionExtensions.ThrowIfNullOrEmpty(dto.ClientId); + + await UpsertClientConfigAsync(dto.ClientId, dto.PasswordRule, dto.SmsTemplates, dto.EmailTemplates); + } + + /// + /// Shared by the standalone and by Add/UpdateClientAsync, + /// since the frontend now saves password rule + message templates together with the Client itself. + /// + private async Task UpsertClientConfigAsync( + string clientId, + ClientPasswordRuleDto? passwordRule, + IEnumerable smsTemplates, + IEnumerable emailTemplates) + { + passwordRule = ClientPasswordRuleRegexConverter.Normalize(passwordRule); + var passwordRuleRegex = ClientPasswordRuleRegexConverter.ToRegex(passwordRule); + var passwordPrompt = passwordRule.PasswordPrompt; + var passwordRuleConfig = ClientPasswordRuleRegexConverter.ToDomainConfig(passwordRule); + var templates = smsTemplates + .Select(t => new ClientMessageTemplate(ChannelTypes.Sms, (int)t.Scene, t.ChannelCode, t.TemplateCode)) + .Concat(emailTemplates + .Select(t => new ClientMessageTemplate(ChannelTypes.Email, (int)t.Scene, t.ChannelCode, t.TemplateCode))); + + var clientConfig = await _clientConfigRepository.FindByClientIdAsync(clientId); + if (clientConfig is null) + { + clientConfig = new ClientConfig(clientId); + clientConfig.UpdatePasswordRule(passwordRuleRegex, passwordPrompt, passwordRuleConfig); + clientConfig.SetMessageTemplates(templates); + await _clientConfigRepository.AddAsync(clientConfig); + } + else + { + clientConfig.UpdatePasswordRule(passwordRuleRegex, passwordPrompt, passwordRuleConfig); + clientConfig.SetMessageTemplates(templates); + await _clientConfigRepository.UpdateAsync(clientConfig); + } + } + #endregion #region IdentityResource diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Sso/Commands/UpsertClientConfigCommand.cs b/src/Services/Masa.Auth.Service.Admin/Application/Sso/Commands/UpsertClientConfigCommand.cs new file mode 100644 index 00000000..8d6e19a7 --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Application/Sso/Commands/UpsertClientConfigCommand.cs @@ -0,0 +1,8 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Service.Admin.Application.Sso.Commands; + +public record UpsertClientConfigCommand(ClientConfigDto ClientConfig) : Command +{ +} diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Sso/Queries/ClientConfigDetailQuery.cs b/src/Services/Masa.Auth.Service.Admin/Application/Sso/Queries/ClientConfigDetailQuery.cs new file mode 100644 index 00000000..3de7a7e4 --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Application/Sso/Queries/ClientConfigDetailQuery.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Service.Admin.Application.Sso.Queries; + +public record ClientConfigDetailQuery(string ClientId) : Query +{ + public override ClientConfigDto Result { get; set; } = new(); +} diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Sso/QueryHandler.cs b/src/Services/Masa.Auth.Service.Admin/Application/Sso/QueryHandler.cs index f77ab879..23820f5f 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Sso/QueryHandler.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Sso/QueryHandler.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the Apache License. See LICENSE.txt in the project root for license information. namespace Masa.Auth.Service.Admin.Application.Sso; @@ -16,6 +16,7 @@ public class QueryHandler private readonly OperaterProvider _operaterProvider; private readonly ILogger _logger; private readonly IMultiEnvironmentContext _environmentContext; + private readonly IClientConfigRepository _clientConfigRepository; public QueryHandler( IClientRepository clientRepository, @@ -28,7 +29,8 @@ public QueryHandler( AuthDbContext authDbContext, OperaterProvider operaterProvider, ILogger logger, - IMultiEnvironmentContext environmentContext) + IMultiEnvironmentContext environmentContext, + IClientConfigRepository clientConfigRepository) { _clientRepository = clientRepository; _identityResourceRepository = identityResourceRepository; @@ -41,6 +43,7 @@ public QueryHandler( _operaterProvider = operaterProvider; _logger = logger; _environmentContext = environmentContext; + _clientConfigRepository = clientConfigRepository; } #region Client @@ -62,6 +65,63 @@ public async Task ClientDetailQueryAsync(ClientDetailQuery clientDetailQuery) { var client = await _clientRepository.GetDetailAsync(clientDetailQuery.ClientId); client.Adapt(clientDetailQuery.Result); + + var clientConfig = await _clientConfigRepository.FindByClientIdAsync(client!.ClientId); + var (passwordRule, smsTemplates, emailTemplates) = MapClientConfig(clientConfig); + clientDetailQuery.Result.PasswordRule = passwordRule; + clientDetailQuery.Result.SmsTemplates = smsTemplates; + clientDetailQuery.Result.EmailTemplates = emailTemplates; + } + + [EventHandler] + public async Task ClientConfigDetailQueryAsync(ClientConfigDetailQuery query) + { + var clientConfig = await _clientConfigRepository.FindByClientIdAsync(query.ClientId); + var (passwordRule, smsTemplates, emailTemplates) = MapClientConfig(clientConfig); + query.Result = new ClientConfigDto + { + ClientId = query.ClientId, + PasswordRule = passwordRule, + SmsTemplates = smsTemplates, + EmailTemplates = emailTemplates + }; + } + + /// + /// Shared by ClientDetailQueryAsync and ClientConfigDetailQueryAsync, since the frontend now + /// reads/saves password rule + message templates together with the Client itself. + /// + private static (ClientPasswordRuleDto PasswordRule, List SmsTemplates, List EmailTemplates) MapClientConfig(ClientConfig? clientConfig) + { + if (clientConfig is null) + { + return (new(), new(), new()); + } + + var passwordRule = ClientPasswordRuleRegexConverter.FromStorage( + clientConfig.PasswordRuleConfig, + clientConfig.PasswordRule, + clientConfig.PasswordPrompt); + + return ( + passwordRule, + clientConfig.MessageTemplates + .Where(t => t.ChannelType == ChannelTypes.Sms) + .Select(t => new ClientSmsTemplateDto + { + Scene = (SendMsgCodeTypes)t.Scene, + ChannelCode = t.ChannelCode, + TemplateCode = t.TemplateCode + }).ToList(), + clientConfig.MessageTemplates + .Where(t => t.ChannelType == ChannelTypes.Email) + .Select(t => new ClientEmailTemplateDto + { + Scene = (SendEmailTypes)t.Scene, + ChannelCode = t.ChannelCode, + TemplateCode = t.TemplateCode + }).ToList() + ); } [EventHandler] diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/CommandHandler.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/CommandHandler.cs index 82fe2265..4e4f360e 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/CommandHandler.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/CommandHandler.cs @@ -23,7 +23,7 @@ public class CommandHandler private readonly LdapDomainService _ldapDomainService; private readonly RoleDomainService _roleDomainService; private readonly IUserContext _userContext; - private readonly PasswordHelper _passwordHelper; + private readonly IPasswordRuleProvider _passwordRuleProvider; public CommandHandler( IUserRepository userRepository, @@ -44,7 +44,7 @@ public CommandHandler( LdapDomainService ldapDomainService, RoleDomainService roleDomainService, IUserContext userContext, - PasswordHelper passwordHelper) + IPasswordRuleProvider passwordRuleProvider) { _userRepository = userRepository; _autoCompleteClient = autoCompleteClient; @@ -64,7 +64,7 @@ public CommandHandler( _ldapDomainService = ldapDomainService; _roleDomainService = roleDomainService; _userContext = userContext; - _passwordHelper = passwordHelper; + _passwordRuleProvider = passwordRuleProvider; } #region User @@ -744,8 +744,7 @@ public async Task DeleteAccountAsync(DeleteAccountCommand command) [EventHandler] public async Task GenerateNewPasswordAsync(GenerateNewPasswordCommand command) { - command.Result = _passwordHelper.GenerateNewPassword(); - await Task.CompletedTask; + command.Result = await _passwordRuleProvider.GenerateNewPasswordAsync(); } [EventHandler(2)] diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/AddUserCommandValidator.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/AddUserCommandValidator.cs index 7ba48dd7..2c8568cb 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/AddUserCommandValidator.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/AddUserCommandValidator.cs @@ -5,14 +5,14 @@ namespace Masa.Auth.Service.Admin.Application.Subjects.Commands; public class AddUserCommandValidator : MasaAbstractValidator { - public AddUserCommandValidator(PasswordValidator passwordValidator, PhoneNumberValidator phoneValidator) + public AddUserCommandValidator(PhoneNumberValidator phoneValidator, IPasswordRuleProvider passwordRuleProvider) { RuleFor(command => command.User.DisplayName).MaximumLength(50); RuleFor(command => command.User.Account).MaximumLength(50); WhenNotEmpty(command => command.User.Email, r => r.Email()); WhenNotEmpty(command => command.User.PhoneNumber, r => r.SetValidator(phoneValidator)); WhenNotEmpty(command => command.User.IdCard, r => r.IdCard()); - WhenNotEmpty(command => command.User.Password, r => r.SetValidator(passwordValidator)); + WhenNotEmpty(command => command.User.Password, r => r.PasswordRule(passwordRuleProvider, command => command.User.ClientId)); WhenNotEmpty(command => command.User.Name, r => r.ChineseLetterNumber().MaximumLength(20)); WhenNotEmpty(command => command.User.CompanyName, r => r.ChineseLetterNumber().MaximumLength(50)); WhenNotEmpty(command => command.User.Position, r => r.ChineseLetterNumber().MaximumLength(20)); diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommand.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommand.cs index 70002d0a..e3f3565b 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommand.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommand.cs @@ -9,5 +9,11 @@ public record ResetPasswordCommand(ResetPasswordTypes ResetPasswordType, string public string ConfirmPassword { get; set; } = string.Empty; + /// + /// The client the user is resetting their password from. This is an anonymous flow (no login), + /// so the caller must pass it explicitly - it cannot be resolved from a token. + /// + public string? ClientId { get; set; } + public User? Result { get; set; } } diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs index 697d52cd..2a6163f3 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/ResetPasswordCommandValidator.cs @@ -5,7 +5,7 @@ namespace Masa.Auth.Service.Admin.Application.Subjects.Commands; public class ResetPasswordCommandValidator : AbstractValidator { - public ResetPasswordCommandValidator(PhoneNumberValidator phoneValidator, PasswordValidator passwordValidator) + public ResetPasswordCommandValidator(PhoneNumberValidator phoneValidator, IPasswordRuleProvider passwordRuleProvider) { When(x => x.ResetPasswordType == ResetPasswordTypes.PhoneNumber, () => { @@ -16,7 +16,9 @@ public ResetPasswordCommandValidator(PhoneNumberValidator phoneValidator, Passwo RuleFor(x => x.Voucher).Required().Email(); }); RuleFor(x => x.Captcha).Required(); - RuleFor(x => x.Password).Required().SetValidator(passwordValidator); + // Anonymous forgot-password flow (no login) - the client rule follows whatever ClientId + // the caller passes for this request; falls back to the global DCC rule when absent. + RuleFor(x => x.Password).PasswordRule(passwordRuleProvider, x => x.ClientId); RuleFor(x => x.ConfirmPassword).Equal(x => x.Password); } } diff --git a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/UpdateUserPasswordCommandValidator.cs b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/UpdateUserPasswordCommandValidator.cs index 197945e5..835e48db 100644 --- a/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/UpdateUserPasswordCommandValidator.cs +++ b/src/Services/Masa.Auth.Service.Admin/Application/Subjects/Commands/UpdateUserPasswordCommandValidator.cs @@ -1,16 +1,30 @@ // Copyright (c) MASA Stack All rights reserved. // Licensed under the Apache License. See LICENSE.txt in the project root for license information. +using IdentityModel; + namespace Masa.Auth.Service.Admin.Application.Subjects.Commands; public class UpdateUserPasswordCommandValidator : MasaAbstractValidator { - public UpdateUserPasswordCommandValidator(PasswordValidator passwordValidator) + private readonly IHttpContextAccessor _httpContextAccessor; + + public UpdateUserPasswordCommandValidator( + IHttpContextAccessor httpContextAccessor, + IPasswordRuleProvider passwordRuleProvider) { - RuleFor(command => command.User.NewPassword).SetValidator(passwordValidator); + _httpContextAccessor = httpContextAccessor; + + RuleFor(command => command.User.NewPassword).PasswordRule(passwordRuleProvider, _ => ResolveCurrentClientId()); RuleFor(command => command.User.NewPassword) .Required() .NotEqual(command => command.User.OldPassword) .WithMessage(I18n.T("PasswordSame")); } + + // The user is already logged in here, so the client-specific rule follows the client they're + // currently using (the access token's client_id claim) - not User.ClientId, which only records + // where the account originally registered from. + private string? ResolveCurrentClientId() + => _httpContextAccessor.HttpContext?.User?.FindFirst(JwtClaimTypes.ClientId)?.Value; } diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Email/EmailAgent.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Email/EmailAgent.cs index 7aa29cfa..7ac8b7b1 100644 --- a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Email/EmailAgent.cs +++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Email/EmailAgent.cs @@ -8,18 +8,21 @@ public class EmailAgent : IScopedDependency readonly IMcClient _mcClient; readonly IDistributedCacheClient _distributedCacheClient; readonly IMasaConfiguration _masaConfiguration; + readonly IClientMessageTemplateProvider _clientMessageTemplateProvider; public EmailAgent( IMcClient mcClient, IDistributedCacheClient distributedCacheClient, - IMasaConfiguration masaConfiguration) + IMasaConfiguration masaConfiguration, + IClientMessageTemplateProvider clientMessageTemplateProvider) { _mcClient = mcClient; _distributedCacheClient = distributedCacheClient; _masaConfiguration = masaConfiguration; + _clientMessageTemplateProvider = clientMessageTemplateProvider; } - public async Task SendEmailAsync(SendEmailModel sendEmailModel, TimeSpan? expiration = null) + public async Task SendEmailAsync(SendEmailModel sendEmailModel, string? clientId = null, TimeSpan? expiration = null) { //todo Abstract Factory var sendKey = string.Empty; @@ -60,15 +63,27 @@ public async Task SendEmailAsync(SendEmailModel sendEmailModel, TimeSpan? expira throw new UserFriendlyException(errorCode: UserFriendlyExceptionCodes.EMAIL_SENDED); } - var _emailOptions = _masaConfiguration.ConfigurationApi.GetPublic().GetSection(EmailOptions.Key).Get(); - MasaArgumentException.ThrowIfNull(_emailOptions, nameof(EmailOptions)); + var channelCode = ""; + var templateCode = ""; + var clientTemplate = await _clientMessageTemplateProvider.ResolveAsync(clientId, ChannelTypes.Email, (int)sendEmailModel.SendEmailType); + if (clientTemplate is not null) + { + (channelCode, templateCode) = clientTemplate.Value; + } + else + { + var _emailOptions = _masaConfiguration.ConfigurationApi.GetPublic().GetSection(EmailOptions.Key).Get(); + MasaArgumentException.ThrowIfNull(_emailOptions, nameof(EmailOptions)); + channelCode = _emailOptions.ChannelCode; + templateCode = _emailOptions.TemplateCode; + } var code = Random.Shared.Next(100000, 999999).ToString(); await _mcClient.MessageTaskService.SendTemplateMessageByExternalAsync(new SendTemplateMessageByExternalModel { - ChannelCode = _emailOptions.ChannelCode, + ChannelCode = channelCode, ChannelType = ChannelTypes.Email, - TemplateCode = _emailOptions.TemplateCode, + TemplateCode = templateCode, ReceiverType = SendTargets.Assign, Receivers = new List { diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs new file mode 100644 index 00000000..6f27dc5b --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/ClientMessageTemplateProvider.cs @@ -0,0 +1,33 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Service.Admin.Infrastructure.Message; + +public class ClientMessageTemplateProvider : IClientMessageTemplateProvider, IScopedDependency +{ + private readonly IClientConfigRepository _clientConfigRepository; + + public ClientMessageTemplateProvider(IClientConfigRepository clientConfigRepository) + { + _clientConfigRepository = clientConfigRepository; + } + + public async Task<(string channelCode, string templateCode)?> ResolveAsync(string? clientId, ChannelTypes channelType, int scene) + { + if (string.IsNullOrEmpty(clientId)) + { + return null; + } + + var clientConfig = await _clientConfigRepository.FindByClientIdAsync(clientId); + var template = clientConfig?.MessageTemplates + .FirstOrDefault(t => t.ChannelType == channelType && t.Scene == scene); + + if (template is null || string.IsNullOrEmpty(template.ChannelCode) || string.IsNullOrEmpty(template.TemplateCode)) + { + return null; + } + + return (template.ChannelCode, template.TemplateCode); + } +} diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs new file mode 100644 index 00000000..f461dcd8 --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Message/IClientMessageTemplateProvider.cs @@ -0,0 +1,14 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Service.Admin.Infrastructure.Message; + +/// +/// Resolves the (channel code, template code) a client has configured for a given +/// (channel type, scene). Returns null when the client has no matching configuration, +/// signalling the caller to fall back to the global DCC SmsOptions/EmailOptions. +/// +public interface IClientMessageTemplateProvider +{ + Task<(string channelCode, string templateCode)?> ResolveAsync(string? clientId, ChannelTypes channelType, int scene); +} diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs new file mode 100644 index 00000000..dc4a372a --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Password/PasswordRuleProvider.cs @@ -0,0 +1,137 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +using Fare; + +namespace Masa.Auth.Service.Admin.Infrastructure.Password; + +public class PasswordRuleProvider : IPasswordRuleProvider, IScopedDependency +{ + public const string PASSWORDRULECONFIGNAME = "$public.AppSettings:PasswordRule"; + public const string PASSWORDPROMPTCONFIGNAME = "$public.AppSettings:PasswordPrompt"; + public const string DEFAULTPASSWORDRULE = "^\\S*(?=\\S{6,})(?=\\S*\\d)(?=\\S*[A-Za-z])\\S*$"; + public const string DEFAULTPASSWORDPROMPT = "PasswordValidateFailed"; + + private readonly IClientConfigRepository _clientConfigRepository; + private readonly IMasaConfiguration _masaConfiguration; + private readonly ILogger _logger; + + public PasswordRuleProvider( + IClientConfigRepository clientConfigRepository, + IMasaConfiguration masaConfiguration, + ILogger logger) + { + _clientConfigRepository = clientConfigRepository; + _masaConfiguration = masaConfiguration; + _logger = logger; + } + + public async Task GetFailureAsync(string? password, string? clientId) + { + var (rule, prompt) = await GetEffectiveRuleAsync(clientId); + return ValidatePasswordWithRule(password, rule, prompt); + } + + public Task GenerateNewPasswordAsync() + { + var (passwordRule, _) = GetGlobalPasswordRule(); + return Task.FromResult(GenerateNewPassword(passwordRule)); + } + + private async Task<(string rule, string prompt)> GetEffectiveRuleAsync(string? clientId) + { + // 全局 DCC 配置作为回退默认值 + var (rule, prompt) = GetGlobalPasswordRule(); + + if (!string.IsNullOrEmpty(clientId)) + { + var clientConfig = await _clientConfigRepository.FindByClientIdAsync(clientId); + if (clientConfig is not null && !string.IsNullOrEmpty(clientConfig.PasswordRule)) + { + rule = clientConfig.PasswordRule; + if (!string.IsNullOrEmpty(clientConfig.PasswordPrompt)) + { + prompt = clientConfig.PasswordPrompt; + } + } + } + + return (rule, prompt); + } + + private (string rule, string prompt) GetGlobalPasswordRule() + { + var passwordRule = DEFAULTPASSWORDRULE; + var passwordPrompt = DEFAULTPASSWORDPROMPT; + if (_masaConfiguration != null) + { + try + { + passwordRule = _masaConfiguration.ConfigurationApi.GetPublic().GetValue(PASSWORDRULECONFIGNAME, DEFAULTPASSWORDRULE); + passwordPrompt = _masaConfiguration.ConfigurationApi.GetPublic().GetValue(PASSWORDPROMPTCONFIGNAME, DEFAULTPASSWORDPROMPT); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取密码规则配置时发生错误,使用默认配置。配置名称: {PasswordRuleConfigName}, {PasswordPromptConfigName}", + PASSWORDRULECONFIGNAME, PASSWORDPROMPTCONFIGNAME); + } + } + else + { + _logger.LogWarning("MasaConfiguration 为空,使用默认密码规则配置"); + } + return (passwordRule, passwordPrompt); + } + + private string GenerateNewPassword(string passwordRule) + { + try + { + var xeger = new Xeger(passwordRule); + return xeger.Generate(); + } + catch (Exception ex) + { + _logger.LogError(ex, "生成新密码时发生错误"); + try + { + var defaultXeger = new Xeger(DEFAULTPASSWORDRULE); + return defaultXeger.Generate(); + } + catch (Exception fallbackEx) + { + _logger.LogError(fallbackEx, "使用默认密码规则生成密码时也发生错误"); + throw new InvalidOperationException("无法生成密码", fallbackEx); + } + } + } + + private string? ValidatePasswordWithRule(string? password, string passwordRule, string passwordPrompt) + { + password ??= string.Empty; + try + { + if (Regex.IsMatch(password, passwordRule)) + { + return null; + } + + _logger.LogWarning("密码验证失败,密码不符合规则。规则: {PasswordRule}", passwordRule); + var message = DEFAULTPASSWORDRULE.Equals(passwordRule) ? "PasswordFormatVerificationPrompt" : passwordPrompt; + try + { + message = I18n.T(message); + } + catch (Exception i18nEx) + { + _logger.LogWarning(i18nEx, "获取密码验证失败提示的本地化文本时发生错误,消息键: {MessageKey}", message); + } + return message; + } + catch (Exception ex) + { + _logger.LogError(ex, "密码验证过程中发生异常"); + return "密码验证过程中发生错误"; + } + } +} diff --git a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Sms/Sms.cs b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Sms/Sms.cs index 8801df92..6d0a6060 100644 --- a/src/Services/Masa.Auth.Service.Admin/Infrastructure/Sms/Sms.cs +++ b/src/Services/Masa.Auth.Service.Admin/Infrastructure/Sms/Sms.cs @@ -8,29 +8,46 @@ public class Sms : IScopedDependency readonly IMcClient _mcClient; readonly IDistributedCacheClient _distributedCacheClient; readonly IMasaConfiguration _masaConfiguration; + readonly IClientMessageTemplateProvider _clientMessageTemplateProvider; public Sms( IMcClient mcClient, IDistributedCacheClient distributedCacheClient, - IMasaConfiguration masaConfiguration) + IMasaConfiguration masaConfiguration, + IClientMessageTemplateProvider clientMessageTemplateProvider) { _mcClient = mcClient; _distributedCacheClient = distributedCacheClient; _masaConfiguration = masaConfiguration; + _clientMessageTemplateProvider = clientMessageTemplateProvider; } - public async Task SendMsgCodeAsync(string key, string phoneNumber, TimeSpan? expiration = null) + public async Task SendMsgCodeAsync(string key, string phoneNumber, string? clientId = null, SendMsgCodeTypes scene = default, TimeSpan? expiration = null) { ArgumentExceptionExtensions.ThrowIfNullOrEmpty(phoneNumber); - var _smsOptions = _masaConfiguration.ConfigurationApi.GetPublic().GetSection(SmsOptions.Key).Get(); - MasaArgumentException.ThrowIfNull(_smsOptions, nameof(SmsOptions)); + + // Client-level template takes precedence; fall back to the global DCC SmsOptions. + var channelCode = ""; + var templateCode = ""; + var clientTemplate = await _clientMessageTemplateProvider.ResolveAsync(clientId, ChannelTypes.Sms, (int)scene); + if (clientTemplate is not null) + { + (channelCode, templateCode) = clientTemplate.Value; + } + else + { + var _smsOptions = _masaConfiguration.ConfigurationApi.GetPublic().GetSection(SmsOptions.Key).Get(); + MasaArgumentException.ThrowIfNull(_smsOptions, nameof(SmsOptions)); + channelCode = _smsOptions.ChannelCode; + templateCode = _smsOptions.TemplateCode; + } var code = Random.Shared.Next(100000, 999999).ToString(); await _mcClient.MessageTaskService.SendTemplateMessageByExternalAsync(new SendTemplateMessageByExternalModel { - ChannelCode = _smsOptions.ChannelCode, + ChannelCode = channelCode, ChannelType = ChannelTypes.Sms, - TemplateCode = _smsOptions.TemplateCode, + TemplateCode = templateCode, ReceiverType = SendTargets.Assign, Receivers = new List { diff --git a/src/Services/Masa.Auth.Service.Admin/Masa.Auth.Service.Admin.csproj b/src/Services/Masa.Auth.Service.Admin/Masa.Auth.Service.Admin.csproj index cc4ac6e8..29473b26 100644 --- a/src/Services/Masa.Auth.Service.Admin/Masa.Auth.Service.Admin.csproj +++ b/src/Services/Masa.Auth.Service.Admin/Masa.Auth.Service.Admin.csproj @@ -29,7 +29,6 @@ - diff --git a/src/Services/Masa.Auth.Service.Admin/Services/ClientConfigService.cs b/src/Services/Masa.Auth.Service.Admin/Services/ClientConfigService.cs new file mode 100644 index 00000000..551920ef --- /dev/null +++ b/src/Services/Masa.Auth.Service.Admin/Services/ClientConfigService.cs @@ -0,0 +1,31 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Service.Admin.Services; + +public class ClientConfigService : ServiceBase +{ + public ClientConfigService() : base("api/sso/client-config") + { + RouteHandlerBuilder = builder => + { + builder.RequireAuthorization(); + }; + + MapGet(GetDetailAsync); + MapPost(UpsertAsync).RequireAuthorization(); + } + + private async Task GetDetailAsync(IEventBus eventBus, [FromQuery] string clientId) + { + var query = new ClientConfigDetailQuery(clientId); + await eventBus.PublishAsync(query); + return query.Result; + } + + private async Task UpsertAsync(IEventBus eventBus, [FromBody] ClientConfigDto clientConfigDto) + { + var command = new UpsertClientConfigCommand(clientConfigDto); + await eventBus.PublishAsync(command); + } +} diff --git a/src/Services/Masa.Auth.Service.Admin/Services/UserService.cs b/src/Services/Masa.Auth.Service.Admin/Services/UserService.cs index 430cd44a..ae69357e 100644 --- a/src/Services/Masa.Auth.Service.Admin/Services/UserService.cs +++ b/src/Services/Masa.Auth.Service.Admin/Services/UserService.cs @@ -340,7 +340,8 @@ public async Task ResetPasswordByPhoneAsync(IEventBus eventBus, [FromBody] var command = new ResetPasswordCommand(ResetPasswordTypes.PhoneNumber, model.PhoneNumber, model.Code) { Password = model.Password, - ConfirmPassword = model.ConfirmPassword + ConfirmPassword = model.ConfirmPassword, + ClientId = model.ClientId }; await eventBus.PublishAsync(command); return true; @@ -353,7 +354,8 @@ public async Task ResetPasswordByEmailAsync(IEventBus eventBus, [FromBody] var command = new ResetPasswordCommand(ResetPasswordTypes.Email, model.Email, model.Code) { Password = model.Password, - ConfirmPassword = model.ConfirmPassword + ConfirmPassword = model.ConfirmPassword, + ClientId = model.ClientId }; await eventBus.PublishAsync(command); return true; diff --git a/src/Services/Masa.Auth.Service.Admin/_Imports.cs b/src/Services/Masa.Auth.Service.Admin/_Imports.cs index 72346744..9ab59f57 100644 --- a/src/Services/Masa.Auth.Service.Admin/_Imports.cs +++ b/src/Services/Masa.Auth.Service.Admin/_Imports.cs @@ -81,6 +81,7 @@ global using Masa.Auth.Service.Admin.Infrastructure.CacheModels; global using Masa.Auth.Service.Admin.Infrastructure.Email; global using Masa.Auth.Service.Admin.Infrastructure.Extensions; +global using Masa.Auth.Service.Admin.Infrastructure.Message; global using Masa.Auth.Service.Admin.Infrastructure.Middleware; global using Masa.Auth.Service.Admin.Infrastructure.Models; global using Masa.Auth.Service.Admin.Infrastructure.Sms;