From 6f84a9c01113dae6310d1000b7dafe25f496c031 Mon Sep 17 00:00:00 2001 From: colin Date: Sat, 25 Apr 2026 10:44:05 +0800 Subject: [PATCH 01/40] fix: Fix the build error --- aspnet-core/LINGYUN.MicroService.All.slnx | 9 ++++ aspnet-core/LINGYUN.MicroService.Aspire.slnx | 7 --- .../FodyWeavers.xsd | 30 ++++++++++++ .../LINGYUN.Abp.Core/AbpCommonModule.cs | 7 --- .../DynamicOptionsProvider.cs | 29 ------------ .../LINGYUN.Abp.Core/IOptionsProvider.cs | 7 --- .../common/LINGYUN.Abp.Core/README.EN.md | 46 ------------------- .../common/LINGYUN.Abp.Core/README.md | 46 ------------------- .../LY.AIO.Applications.Single.csproj | 2 +- build/build-aspnetcore-common.ps1 | 1 + 10 files changed, 41 insertions(+), 143 deletions(-) create mode 100644 aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xsd delete mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Core/AbpCommonModule.cs delete mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Core/DynamicOptionsProvider.cs delete mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Core/IOptionsProvider.cs delete mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Core/README.EN.md delete mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Core/README.md diff --git a/aspnet-core/LINGYUN.MicroService.All.slnx b/aspnet-core/LINGYUN.MicroService.All.slnx index 3b8dc3c56..011923378 100644 --- a/aspnet-core/LINGYUN.MicroService.All.slnx +++ b/aspnet-core/LINGYUN.MicroService.All.slnx @@ -1,4 +1,11 @@ + + + + + + + @@ -85,6 +92,7 @@ + @@ -116,6 +124,7 @@ + diff --git a/aspnet-core/LINGYUN.MicroService.Aspire.slnx b/aspnet-core/LINGYUN.MicroService.Aspire.slnx index d5539f4c5..166412f51 100644 --- a/aspnet-core/LINGYUN.MicroService.Aspire.slnx +++ b/aspnet-core/LINGYUN.MicroService.Aspire.slnx @@ -228,10 +228,6 @@ - - - - @@ -568,9 +564,6 @@ - - - diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xsd b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Core/AbpCommonModule.cs b/aspnet-core/framework/common/LINGYUN.Abp.Core/AbpCommonModule.cs deleted file mode 100644 index 1a9e1da7d..000000000 --- a/aspnet-core/framework/common/LINGYUN.Abp.Core/AbpCommonModule.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Volo.Abp.Modularity; - -namespace LINGYUN.Abp; - -public class AbpCommonModule : AbpModule -{ -} diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Core/DynamicOptionsProvider.cs b/aspnet-core/framework/common/LINGYUN.Abp.Core/DynamicOptionsProvider.cs deleted file mode 100644 index ba0f722da..000000000 --- a/aspnet-core/framework/common/LINGYUN.Abp.Core/DynamicOptionsProvider.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.Extensions.Options; -using System; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Threading; - -namespace LINGYUN.Abp; - -public class DynamicOptionsProvider : IOptionsProvider, ITransientDependency - where TValue : class, new() -{ - public TValue Value => _lazyValueFactory.Value; - - private readonly Lazy _lazyValueFactory; - private readonly OneTimeRunner _oneTimeRunner; - - public DynamicOptionsProvider(IOptions options) - { - _oneTimeRunner = new OneTimeRunner(); - _lazyValueFactory = new Lazy(() => CreateOptions(options)); - } - - protected virtual TValue CreateOptions(IOptions options) - { - // 用于简化需要在使用配置前自行调用此接口的繁复步骤 - // await options.SetAsync(); - // _onTimeRunner.Run(async () => await options.SetAsync()); - return options.Value; - } -} diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Core/IOptionsProvider.cs b/aspnet-core/framework/common/LINGYUN.Abp.Core/IOptionsProvider.cs deleted file mode 100644 index f6a736afa..000000000 --- a/aspnet-core/framework/common/LINGYUN.Abp.Core/IOptionsProvider.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace LINGYUN.Abp; - -public interface IOptionsProvider - where TValue: class, new() -{ - TValue Value { get; } -} diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Core/README.EN.md b/aspnet-core/framework/common/LINGYUN.Abp.Core/README.EN.md deleted file mode 100644 index 2bb4de3eb..000000000 --- a/aspnet-core/framework/common/LINGYUN.Abp.Core/README.EN.md +++ /dev/null @@ -1,46 +0,0 @@ -# LINGYUN.Abp.Core - -## Introduction - -`LINGYUN.Abp.Core` is a basic core module that provides some common functionalities and extensions. - -## Features - -* Dynamic Options Provider (`DynamicOptionsProvider`) - * Simplifies the complex steps of calling interfaces before using configuration - * Supports lazy loading of configuration values - * Provides one-time running mechanism to ensure configuration is loaded only once - -## Installation - -```bash -dotnet add package LINGYUN.Abp.Core -``` - -## Usage - -1. Add `[DependsOn(typeof(AbpCommonModule))]` to your module class. - -```csharp -[DependsOn(typeof(AbpCommonModule))] -public class YourModule : AbpModule -{ - // ... -} -``` - -2. Use Dynamic Options Provider: - -```csharp -public class YourOptionsProvider : DynamicOptionsProvider -{ - public YourOptionsProvider(IOptions options) - : base(options) - { - } -} -``` - -## Links - -* [中文文档](./README.md) diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Core/README.md b/aspnet-core/framework/common/LINGYUN.Abp.Core/README.md deleted file mode 100644 index 6afd486dd..000000000 --- a/aspnet-core/framework/common/LINGYUN.Abp.Core/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# LINGYUN.Abp.Core - -## 介绍 - -`LINGYUN.Abp.Core` 是一个基础核心模块,提供了一些通用的功能和扩展。 - -## 功能 - -* 动态选项提供者 (`DynamicOptionsProvider`) - * 简化需要在使用配置前自行调用接口的繁复步骤 - * 支持延迟加载配置值 - * 提供一次性运行机制,确保配置只被加载一次 - -## 安装 - -```bash -dotnet add package LINGYUN.Abp.Core -``` - -## 使用 - -1. 添加 `[DependsOn(typeof(AbpCommonModule))]` 到你的模块类上。 - -```csharp -[DependsOn(typeof(AbpCommonModule))] -public class YourModule : AbpModule -{ - // ... -} -``` - -2. 使用动态选项提供者: - -```csharp -public class YourOptionsProvider : DynamicOptionsProvider -{ - public YourOptionsProvider(IOptions options) - : base(options) - { - } -} -``` - -## 链接 - -* [English document](./README.EN.md) diff --git a/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj b/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj index f2846373c..1c3337679 100644 --- a/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj +++ b/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj @@ -27,7 +27,7 @@ - + diff --git a/build/build-aspnetcore-common.ps1 b/build/build-aspnetcore-common.ps1 index 1019e0dfa..17f3056a5 100644 --- a/build/build-aspnetcore-common.ps1 +++ b/build/build-aspnetcore-common.ps1 @@ -20,6 +20,7 @@ $serviceArray += [PsObject]@{ Path = $rootFolder + "/../gateways/internal/LINGYU [PsObject[]]$solutionArray = @() $solutionArray += [PsObject]@{ File = $rootFolder + "/../aspnet-core/LINGYUN.MicroService.All.slnx" } +$solutionArray += [PsObject]@{ File = $rootFolder + "/../aspnet-core/LINGYUN.MicroService.Aspire.slnx" } $solutionArray += [PsObject]@{ File = $rootFolder + "/../aspnet-core/LINGYUN.MicroService.SingleProject.slnx" } $solutionArray += [PsObject]@{ File = $rootFolder + "/../gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.slnx" } From ee1d30633a8f4289f0fce80aa14a77108fc7c85a Mon Sep 17 00:00:00 2001 From: colin Date: Sat, 25 Apr 2026 11:06:07 +0800 Subject: [PATCH 02/40] fix: fixed MiniExcel Export settings --- .../LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs | 2 +- .../Abp/Exporter/MiniSoftware/MiniExcelImporterProvider.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs index 582877234..f1c434203 100644 --- a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs @@ -27,7 +27,7 @@ public class MiniExcelImporterProvider : IImporterProvider, ITransientDependency { var xmlConfig = new OpenXmlConfiguration(); - if (_options.ExportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) + if (_options.ImportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) { exportSetting?.Invoke(xmlConfig); } diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniSoftware/LINGYUN/Abp/Exporter/MiniSoftware/MiniExcelImporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniSoftware/LINGYUN/Abp/Exporter/MiniSoftware/MiniExcelImporterProvider.cs index d3319839e..9aaeb2f00 100644 --- a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniSoftware/LINGYUN/Abp/Exporter/MiniSoftware/MiniExcelImporterProvider.cs +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniSoftware/LINGYUN/Abp/Exporter/MiniSoftware/MiniExcelImporterProvider.cs @@ -31,7 +31,7 @@ public class MiniExcelImporterProvider : { var xmlConfig = new OpenXmlConfiguration(); - if (_options.ExportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) + if (_options.ImportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) { exportSetting?.Invoke(xmlConfig); } From 7ff722a3577c51e98f541e3b42193ecf2f3d2dde Mon Sep 17 00:00:00 2001 From: colin Date: Sat, 25 Apr 2026 14:21:48 +0800 Subject: [PATCH 03/40] feat: Adjust the microservice template project --- .../LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj | 6 +- ...PackageName.CompanyName.ProjectName.csproj | 4 +- .../templates/micro/content/.gitlab-ci.yml | 2 - .../content/{deploy => .k8s}/deployment.yaml | 0 .../micro/content/Directory.Packages.props | 80 +++++---- .../PackageName.CompanyName.ProjectName.sln | 166 ------------------ .../PackageName.CompanyName.ProjectName.slnx | 44 +++++ .../templates/micro/content/common.props | 4 +- .../deploy/docker-compose.override.yml | 9 - .../content/{deploy => }/docker-compose.yml | 7 + .../Dockerfile | 41 ++++- ...ompanyName.ProjectName.HttpApi.Host.csproj | 4 +- .../ProjectNameHttpApiHostModule.Configure.cs | 48 +++-- .../ProjectNameHttpApiHostModule.cs | 10 +- .../SwaggerGen/EnumDescriptionSchemaFilter.cs | 41 +++++ .../SwaggerGen/TenantHeaderParamter.cs | 35 ++++ .../TenantHeaderParamter.cs | 31 ---- .../appsettings.Development.json | 30 ++-- .../appsettings.json | 140 ++++++++------- ...Name.DbMigrator.EntityFrameworkCore.csproj | 11 +- .../ProjectNameDataSeeder.cs | 29 +++ .../ProjectNameDbMigrationEventHandler.cs | 19 +- .../ProjectNameDbMigrationService.cs | 40 +---- ...NameDbMigratorEntityFrameworkCoreModule.cs | 19 +- .../appsettings.json | 9 +- .../ProjectNameApplicationMapperProfile.cs | 10 -- .../ProjectNameApplicationMappers.cs | 15 ++ .../ProjectNameApplicationModule.cs | 8 +- ...Name.CompanyName.ProjectName.Domain.csproj | 2 +- .../IProjectNameBasicRepository.cs | 23 +-- .../IProjectNameDataProtectionRepository.cs | 15 ++ .../ProjectNameDataSeedContributor.cs | 22 --- .../ProjectNameDomainMapperProfile.cs | 11 -- .../ProjectName/ProjectNameDomainMappers.cs | 16 ++ .../ProjectName/ProjectNameDomainModule.cs | 14 +- .../EfCoreProjectNameBasicRepository.cs | 57 ++++++ ...oreProjectNameDataProtectionRepository.cs} | 23 +-- .../ProjectNameEntityFrameworkCoreModule.cs | 10 ++ ...yName.ProjectName.Application.Tests.csproj | 24 +-- ...ompanyName.ProjectName.Domain.Tests.csproj | 24 +-- ...me.CompanyName.ProjectName.TestBase.csproj | 36 ++-- 41 files changed, 580 insertions(+), 559 deletions(-) rename aspnet-core/templates/micro/content/{deploy => .k8s}/deployment.yaml (100%) delete mode 100644 aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.sln create mode 100644 aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.slnx delete mode 100644 aspnet-core/templates/micro/content/deploy/docker-compose.override.yml rename aspnet-core/templates/micro/content/{deploy => }/docker-compose.yml (62%) create mode 100644 aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/EnumDescriptionSchemaFilter.cs create mode 100644 aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/TenantHeaderParamter.cs delete mode 100644 aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs create mode 100644 aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDataSeeder.cs delete mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs create mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMappers.cs create mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameDataProtectionRepository.cs delete mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDataSeedContributor.cs delete mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs create mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMappers.cs create mode 100644 aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameBasicRepository.cs rename aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/{EfCoreProjectNameRepository.cs => EfCoreProjectNameDataProtectionRepository.cs} (73%) diff --git a/aspnet-core/framework/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj b/aspnet-core/framework/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj index c609670ac..d5c4c19c6 100644 --- a/aspnet-core/framework/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj +++ b/aspnet-core/framework/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj @@ -1,11 +1,11 @@ - + Exe net10.0 - 9.3.6 + 10.2.0 colin Use LINGYUN.MicroService.Templates command line true @@ -28,7 +28,7 @@ - + diff --git a/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj b/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj index e53952932..0bbc1910a 100644 --- a/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj +++ b/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj @@ -3,7 +3,7 @@ net10.0 true LINGYUN.Abp.MicroService.Templates - 9.3.6 + 10.2.0 colin.in@foxmail.com Abp framework micro-service template MIT @@ -27,4 +27,4 @@ content - \ No newline at end of file + diff --git a/aspnet-core/templates/micro/content/.gitlab-ci.yml b/aspnet-core/templates/micro/content/.gitlab-ci.yml index 40e9f2c72..ac142b284 100644 --- a/aspnet-core/templates/micro/content/.gitlab-ci.yml +++ b/aspnet-core/templates/micro/content/.gitlab-ci.yml @@ -1,5 +1,3 @@ -image: mcr.microsoft.com/dotnet/sdk:9.0 - stages: - build - test diff --git a/aspnet-core/templates/micro/content/deploy/deployment.yaml b/aspnet-core/templates/micro/content/.k8s/deployment.yaml similarity index 100% rename from aspnet-core/templates/micro/content/deploy/deployment.yaml rename to aspnet-core/templates/micro/content/.k8s/deployment.yaml diff --git a/aspnet-core/templates/micro/content/Directory.Packages.props b/aspnet-core/templates/micro/content/Directory.Packages.props index de3aa0208..7e7b4d4a5 100644 --- a/aspnet-core/templates/micro/content/Directory.Packages.props +++ b/aspnet-core/templates/micro/content/Directory.Packages.props @@ -1,12 +1,12 @@ - 8.3.5 - 2.15.1 - 9.3.6 - 9.3.6 - 9.0.5 - 9.0.5 - 9.0.5 + 10.0.0 + 2.16.1 + 10.2.0 + 10.2.0 + 10.0.2 + 10.0.2 + 10.0.2 true @@ -21,6 +21,7 @@ + @@ -48,7 +49,7 @@ - + @@ -243,7 +244,7 @@ - + @@ -332,6 +333,7 @@ + @@ -392,9 +394,11 @@ - + + + @@ -430,55 +434,57 @@ - - + + + - - + + - - + + + - + - + - + - + - - - - + + + + - + - + - - - + + + @@ -486,15 +492,15 @@ - - - - + + + + - - - - + + + + diff --git a/aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.sln b/aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.sln deleted file mode 100644 index 86f0bf749..000000000 --- a/aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.sln +++ /dev/null @@ -1,166 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4B0AD527-99B3-49A9-8A45-FD8671F8BE4D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.HttpApi.Host", "host\PackageName.CompanyName.ProjectName.HttpApi.Host\PackageName.CompanyName.ProjectName.HttpApi.Host.csproj", "{31E33CE2-71D3-43FF-9A30-2DCC82C607AE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solution Items", ".Solution Items", "{C9675742-7986-4BC1-9781-FD1C3C5B6287}" - ProjectSection(SolutionItems) = preProject - .gitignore = .gitignore - common.props = common.props - configureawait.props = configureawait.props - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - NuGet.Config = NuGet.Config - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{4786387C-C1C5-46F8-806F-EBC54DB0A4FA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A9CB1547-1C2C-4A23-82EC-C834C1626E0A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Application.Tests", "tests\PackageName.CompanyName.ProjectName.Application.Tests\PackageName.CompanyName.ProjectName.Application.Tests.csproj", "{9262FE7A-76B2-424F-8C34-AFA1D95D7E5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Domain.Tests", "tests\PackageName.CompanyName.ProjectName.Domain.Tests\PackageName.CompanyName.ProjectName.Domain.Tests.csproj", "{A0D1F8A4-3494-4E26-9E2D-DB874B93DBCE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests", "tests\PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests\PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj", "{0B2E1C9E-092D-4E5F-BE9F-5506E689FC85}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.TestBase", "tests\PackageName.CompanyName.ProjectName.TestBase\PackageName.CompanyName.ProjectName.TestBase.csproj", "{4A9D43A2-D08B-40E8-9C74-F2B95BF81AED}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.DbMigrator", "migrations\PackageName.CompanyName.ProjectName.DbMigrator\PackageName.CompanyName.ProjectName.DbMigrator.csproj", "{F6EE5BCD-69C7-4C8A-8B45-251AFE2BB01E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Domain.Shared", "src\PackageName.CompanyName.ProjectName.Domain.Shared\PackageName.CompanyName.ProjectName.Domain.Shared.csproj", "{77090F97-BD80-4469-842F-F5769CF849E9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Domain", "src\PackageName.CompanyName.ProjectName.Domain\PackageName.CompanyName.ProjectName.Domain.csproj", "{DF2CCF03-95D5-4BE4-8B32-742818C56F15}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Application.Contracts", "src\PackageName.CompanyName.ProjectName.Application.Contracts\PackageName.CompanyName.ProjectName.Application.Contracts.csproj", "{54FB9929-7D9C-40FC-A0D0-94ACBA37D20E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Application", "src\PackageName.CompanyName.ProjectName.Application\PackageName.CompanyName.ProjectName.Application.csproj", "{F2A6182F-BCB9-4C80-947C-0A2ED1B6BFDB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.Dapr.Client", "src\PackageName.CompanyName.ProjectName.Dapr.Client\PackageName.CompanyName.ProjectName.Dapr.Client.csproj", "{B69F04FF-8505-49F6-9B60-BB800846C87C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.EntityFrameworkCore", "src\PackageName.CompanyName.ProjectName.EntityFrameworkCore\PackageName.CompanyName.ProjectName.EntityFrameworkCore.csproj", "{09CA7186-DBA7-4428-A1ED-31292AC02050}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.HttpApi", "src\PackageName.CompanyName.ProjectName.HttpApi\PackageName.CompanyName.ProjectName.HttpApi.csproj", "{FDB3A3E9-C072-438D-8B8D-2AA957C1167F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.HttpApi.Client", "src\PackageName.CompanyName.ProjectName.HttpApi.Client\PackageName.CompanyName.ProjectName.HttpApi.Client.csproj", "{8CE7C515-CD78-42D4-A9D7-39D217A3D046}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PackageName.CompanyName.ProjectName.SettingManagement", "src\PackageName.CompanyName.ProjectName.SettingManagement\PackageName.CompanyName.ProjectName.SettingManagement.csproj", "{CAEB3435-A332-4FFA-BE5F-4E386FA8B19B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore", "migrations\PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore\PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore.csproj", "{285408F0-EF7A-41B8-9828-A9B9C84E635F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "migrations", "migrations", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" - ProjectSection(SolutionItems) = preProject - migrations\migrations-database.ps1 = migrations\migrations-database.ps1 - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".deploy", ".deploy", "{46954769-3C8A-4E05-912A-91B896A91B97}" - ProjectSection(SolutionItems) = preProject - deploy\deployment.yaml = deploy\deployment.yaml - deploy\docker-compose.override.yml = deploy\docker-compose.override.yml - deploy\docker-compose.yml = deploy\docker-compose.yml - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".workflows", ".workflows", "{CE7B8857-00E7-4903-A7C1-0285398616A8}" - ProjectSection(SolutionItems) = preProject - .gitlab-ci.yml = .gitlab-ci.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {31E33CE2-71D3-43FF-9A30-2DCC82C607AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {31E33CE2-71D3-43FF-9A30-2DCC82C607AE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {31E33CE2-71D3-43FF-9A30-2DCC82C607AE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {31E33CE2-71D3-43FF-9A30-2DCC82C607AE}.Release|Any CPU.Build.0 = Release|Any CPU - {9262FE7A-76B2-424F-8C34-AFA1D95D7E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9262FE7A-76B2-424F-8C34-AFA1D95D7E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9262FE7A-76B2-424F-8C34-AFA1D95D7E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9262FE7A-76B2-424F-8C34-AFA1D95D7E5A}.Release|Any CPU.Build.0 = Release|Any CPU - {A0D1F8A4-3494-4E26-9E2D-DB874B93DBCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0D1F8A4-3494-4E26-9E2D-DB874B93DBCE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0D1F8A4-3494-4E26-9E2D-DB874B93DBCE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0D1F8A4-3494-4E26-9E2D-DB874B93DBCE}.Release|Any CPU.Build.0 = Release|Any CPU - {0B2E1C9E-092D-4E5F-BE9F-5506E689FC85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B2E1C9E-092D-4E5F-BE9F-5506E689FC85}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B2E1C9E-092D-4E5F-BE9F-5506E689FC85}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0B2E1C9E-092D-4E5F-BE9F-5506E689FC85}.Release|Any CPU.Build.0 = Release|Any CPU - {4A9D43A2-D08B-40E8-9C74-F2B95BF81AED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A9D43A2-D08B-40E8-9C74-F2B95BF81AED}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A9D43A2-D08B-40E8-9C74-F2B95BF81AED}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A9D43A2-D08B-40E8-9C74-F2B95BF81AED}.Release|Any CPU.Build.0 = Release|Any CPU - {F6EE5BCD-69C7-4C8A-8B45-251AFE2BB01E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6EE5BCD-69C7-4C8A-8B45-251AFE2BB01E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6EE5BCD-69C7-4C8A-8B45-251AFE2BB01E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6EE5BCD-69C7-4C8A-8B45-251AFE2BB01E}.Release|Any CPU.Build.0 = Release|Any CPU - {77090F97-BD80-4469-842F-F5769CF849E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77090F97-BD80-4469-842F-F5769CF849E9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77090F97-BD80-4469-842F-F5769CF849E9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77090F97-BD80-4469-842F-F5769CF849E9}.Release|Any CPU.Build.0 = Release|Any CPU - {DF2CCF03-95D5-4BE4-8B32-742818C56F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF2CCF03-95D5-4BE4-8B32-742818C56F15}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF2CCF03-95D5-4BE4-8B32-742818C56F15}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF2CCF03-95D5-4BE4-8B32-742818C56F15}.Release|Any CPU.Build.0 = Release|Any CPU - {54FB9929-7D9C-40FC-A0D0-94ACBA37D20E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54FB9929-7D9C-40FC-A0D0-94ACBA37D20E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54FB9929-7D9C-40FC-A0D0-94ACBA37D20E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54FB9929-7D9C-40FC-A0D0-94ACBA37D20E}.Release|Any CPU.Build.0 = Release|Any CPU - {F2A6182F-BCB9-4C80-947C-0A2ED1B6BFDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F2A6182F-BCB9-4C80-947C-0A2ED1B6BFDB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2A6182F-BCB9-4C80-947C-0A2ED1B6BFDB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F2A6182F-BCB9-4C80-947C-0A2ED1B6BFDB}.Release|Any CPU.Build.0 = Release|Any CPU - {B69F04FF-8505-49F6-9B60-BB800846C87C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B69F04FF-8505-49F6-9B60-BB800846C87C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B69F04FF-8505-49F6-9B60-BB800846C87C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B69F04FF-8505-49F6-9B60-BB800846C87C}.Release|Any CPU.Build.0 = Release|Any CPU - {09CA7186-DBA7-4428-A1ED-31292AC02050}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {09CA7186-DBA7-4428-A1ED-31292AC02050}.Debug|Any CPU.Build.0 = Debug|Any CPU - {09CA7186-DBA7-4428-A1ED-31292AC02050}.Release|Any CPU.ActiveCfg = Release|Any CPU - {09CA7186-DBA7-4428-A1ED-31292AC02050}.Release|Any CPU.Build.0 = Release|Any CPU - {FDB3A3E9-C072-438D-8B8D-2AA957C1167F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FDB3A3E9-C072-438D-8B8D-2AA957C1167F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FDB3A3E9-C072-438D-8B8D-2AA957C1167F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FDB3A3E9-C072-438D-8B8D-2AA957C1167F}.Release|Any CPU.Build.0 = Release|Any CPU - {8CE7C515-CD78-42D4-A9D7-39D217A3D046}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8CE7C515-CD78-42D4-A9D7-39D217A3D046}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CE7C515-CD78-42D4-A9D7-39D217A3D046}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8CE7C515-CD78-42D4-A9D7-39D217A3D046}.Release|Any CPU.Build.0 = Release|Any CPU - {CAEB3435-A332-4FFA-BE5F-4E386FA8B19B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CAEB3435-A332-4FFA-BE5F-4E386FA8B19B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CAEB3435-A332-4FFA-BE5F-4E386FA8B19B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CAEB3435-A332-4FFA-BE5F-4E386FA8B19B}.Release|Any CPU.Build.0 = Release|Any CPU - {285408F0-EF7A-41B8-9828-A9B9C84E635F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {285408F0-EF7A-41B8-9828-A9B9C84E635F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {285408F0-EF7A-41B8-9828-A9B9C84E635F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {285408F0-EF7A-41B8-9828-A9B9C84E635F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {31E33CE2-71D3-43FF-9A30-2DCC82C607AE} = {4786387C-C1C5-46F8-806F-EBC54DB0A4FA} - {9262FE7A-76B2-424F-8C34-AFA1D95D7E5A} = {A9CB1547-1C2C-4A23-82EC-C834C1626E0A} - {A0D1F8A4-3494-4E26-9E2D-DB874B93DBCE} = {A9CB1547-1C2C-4A23-82EC-C834C1626E0A} - {0B2E1C9E-092D-4E5F-BE9F-5506E689FC85} = {A9CB1547-1C2C-4A23-82EC-C834C1626E0A} - {4A9D43A2-D08B-40E8-9C74-F2B95BF81AED} = {A9CB1547-1C2C-4A23-82EC-C834C1626E0A} - {F6EE5BCD-69C7-4C8A-8B45-251AFE2BB01E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - {77090F97-BD80-4469-842F-F5769CF849E9} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {DF2CCF03-95D5-4BE4-8B32-742818C56F15} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {54FB9929-7D9C-40FC-A0D0-94ACBA37D20E} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {F2A6182F-BCB9-4C80-947C-0A2ED1B6BFDB} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {B69F04FF-8505-49F6-9B60-BB800846C87C} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {09CA7186-DBA7-4428-A1ED-31292AC02050} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {FDB3A3E9-C072-438D-8B8D-2AA957C1167F} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {8CE7C515-CD78-42D4-A9D7-39D217A3D046} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {CAEB3435-A332-4FFA-BE5F-4E386FA8B19B} = {4B0AD527-99B3-49A9-8A45-FD8671F8BE4D} - {285408F0-EF7A-41B8-9828-A9B9C84E635F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {62C0F185-E2C2-46A2-B4B2-5E703E25849E} - EndGlobalSection -EndGlobal diff --git a/aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.slnx b/aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.slnx new file mode 100644 index 000000000..38bbf0bf3 --- /dev/null +++ b/aspnet-core/templates/micro/content/PackageName.CompanyName.ProjectName.slnx @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/micro/content/common.props b/aspnet-core/templates/micro/content/common.props index 76c45eb0d..8729c3ca2 100644 --- a/aspnet-core/templates/micro/content/common.props +++ b/aspnet-core/templates/micro/content/common.props @@ -1,12 +1,12 @@ latest - 9.3.6 + 10.2.0 colin $(NoWarn);CS1591;CS0436;CS8618;NU1803 https://github.com/colinin/abp-next-admin $(SolutionDir)LocalNuget - 9.3.6 + 10.2.0 MIT git https://github.com/colinin/abp-next-admin diff --git a/aspnet-core/templates/micro/content/deploy/docker-compose.override.yml b/aspnet-core/templates/micro/content/deploy/docker-compose.override.yml deleted file mode 100644 index 9dfa8de2a..000000000 --- a/aspnet-core/templates/micro/content/deploy/docker-compose.override.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - project-name-api: - build: - context: ../host/PackageName.CompanyName.ProjectName.HttpApi.Host/bin/Release/net9.0 - dockerfile: ../host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile - volumes: - - /var/opt/project-name/logs:/app/Logs - - /var/opt/project-name/modules:/app/Modules - restart: always diff --git a/aspnet-core/templates/micro/content/deploy/docker-compose.yml b/aspnet-core/templates/micro/content/docker-compose.yml similarity index 62% rename from aspnet-core/templates/micro/content/deploy/docker-compose.yml rename to aspnet-core/templates/micro/content/docker-compose.yml index 2473b0024..d953c8eb6 100644 --- a/aspnet-core/templates/micro/content/deploy/docker-compose.yml +++ b/aspnet-core/templates/micro/content/docker-compose.yml @@ -1,5 +1,8 @@ services: project-name-api: + build: + context: . + dockerfile: host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile hostname: project-name-api container_name: project-name-api environment: @@ -13,3 +16,7 @@ services: interval: 10s timeout: 5s retries: 5 + restart: always + volumes: + - /var/opt/project-name/logs:/app/Logs + - /var/opt/project-name/modules:/app/Modules diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile index 60ef36d4f..f034fe757 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:9.0 +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base LABEL maintainer="colin.in@foxmail.com" WORKDIR /app @@ -43,15 +43,46 @@ COPY . /app #RUN apt-get clean #RUN apt-get update +RUN apt update && apt install wget -y + +USER $APP_UID + ## .NET 8.0 默认使用8080端口,变更为80端口需要环境变量ASPNETCORE_HTTP_PORTS=80 ## .NET 8.0 defaults to port 8080, changing to port 80 requires the environment variable ASPNETCORE.HTTP-PORTS=80 - EXPOSE 8080/tcp VOLUME [ "./app/Logs" ] VOLUME [ "./app/Modules" ] -RUN apt update -RUN apt install wget -y +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /build + +## 复制构建项目所需配置 +COPY ["common.props", "./"] +COPY ["configureawait.props", "./"] +COPY ["Directory.Build.props", "./"] +COPY ["Directory.Packages.props", "./"] +COPY ["NuGet.Config", "./"] -ENTRYPOINT ["dotnet", "PackageName.CompanyName.ProjectName.HttpApi.Host.dll"] +## 复制项目结构 +COPY ["src/", "build/src/"] +COPY ["migrations/", "build/migrations/"] +COPY ["host/", "build/host/"] +RUN dotnet restore "build/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj" + +## 构建 +COPY . . +WORKDIR "/build/host/PackageName.CompanyName.ProjectName.HttpApi.Host" +RUN dotnet build "./PackageName.CompanyName.ProjectName.HttpApi.Host.csproj" -c $BUILD_CONFIGURATION -o /app/build + +## 发布 +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./PackageName.CompanyName.ProjectName.HttpApi.Host.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +## 运行 +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "PackageName.CompanyName.ProjectName.HttpApi.Host.dll"] \ No newline at end of file diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj index f3bdee41c..7865ea71f 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj @@ -19,11 +19,12 @@ + - + @@ -44,6 +45,7 @@ + diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs index eedb595cf..0ab7f0913 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs @@ -2,7 +2,7 @@ using LINGYUN.Abp.Dapr.Client.ClientProxying; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; -using LINGYUN.Abp.Exporter.MiniExcel; +using LINGYUN.Abp.Exporter.MiniSoftware; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.LocalizationManagement; using LINGYUN.Abp.Serilog.Enrichers.Application; @@ -20,8 +20,9 @@ using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using StackExchange.Redis; +using Swashbuckle.AspNetCore.SwaggerGen; using System; using System.Collections.Generic; using System.IO; @@ -137,8 +138,11 @@ public partial class ProjectNameHttpApiHostModule var distributedLockIsEnabled = configuration["DistributedLock:IsEnabled"]; if (distributedLockIsEnabled.IsNullOrWhiteSpace() || bool.Parse(distributedLockIsEnabled)) { - var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); - services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + services.AddSingleton(_ => + { + return new RedisDistributedSynchronizationProvider( + ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]).GetDatabase()); + }); } } private void ConfigureExceptionHandling() @@ -232,12 +236,16 @@ public partial class ProjectNameHttpApiHostModule services.AddHealthChecks(); } - private void ConfigureMiniExcel() + private void ConfigureMiniSoftware() { Configure(options => { // MiniExcel导入导出配置 }); + Configure(options => + { + // MiniWord导入导出配置 + }); } private void ConfigureFeatureManagement(IConfiguration configuration) @@ -368,25 +376,16 @@ public partial class ProjectNameHttpApiHostModule BearerFormat = "JWT" }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } - }, - new string[] { } - } - }); - var currentPath = AppContext.BaseDirectory; var xmlDocFiles = Directory.GetFiles(currentPath, "PackageName.CompanyName.ProjectName.*.xml"); + xmlDocFiles.AddIfNotContains(Directory.GetFiles(AppContext.BaseDirectory, "Volo.Abp.*.xml")); foreach (var xmlDocFile in xmlDocFiles) { options.IncludeXmlComments(xmlDocFile); } + options.SchemaFilter(); options.OperationFilter(); options.HideAbpEndpoints(); }); @@ -426,6 +425,7 @@ public partial class ProjectNameHttpApiHostModule { Configure(options => { + configuration.GetSection("AntiForgery").Bind(options); // options.AutoValidate = false; // options.AutoValidateFilter = (type) => !type.Namespace.Contains("elsa", StringComparison.CurrentCultureIgnoreCase); }); @@ -455,15 +455,13 @@ public partial class ProjectNameHttpApiHostModule options.TokenValidationParameters.ValidAudiences = validAudiences; } }); - - if (!isDevelopment) - { - var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); - services - .AddDataProtection() - .SetApplicationName("LINGYUN.Abp.Application") - .PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); - } + services.AddDataProtection() + .SetApplicationName("LINGYUN.Abp.Application") + .PersistKeysToStackExchangeRedis(() => + { + return ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]).GetDatabase(); + }, + "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); } private void ConfigureCors(IServiceCollection services, IConfiguration configuration) diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs index 0087fc9c8..0f2d15d71 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs @@ -1,19 +1,20 @@ using LINGYUN.Abp.AspNetCore.HttpOverrides; using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; using LINGYUN.Abp.AuditLogging.Elasticsearch; +using LINGYUN.Abp.BlobStoring.BlobManagement; using LINGYUN.Abp.Claims.Mapping; using LINGYUN.Abp.Emailing.Platform; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; -using LINGYUN.Abp.Exporter.MiniExcel; +using LINGYUN.Abp.Exporter.MiniSoftware; using LINGYUN.Abp.Identity.Session.AspNetCore; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LINGYUN.Abp.Sms.Platform; -using LINGYUN.Abp.Telemetry.SkyWalking; using LINGYUN.Abp.Telemetry.OpenTelemetry; +using LINGYUN.Abp.Telemetry.SkyWalking; using LINGYUN.Abp.TextTemplating.EntityFrameworkCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -61,6 +62,7 @@ namespace PackageName.CompanyName.ProjectName; typeof(AbpTextTemplatingEntityFrameworkCoreModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), + typeof(AbpBlobStoringBlobManagementModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpDistributedLockingModule), typeof(AbpAspNetCoreMvcWrapperModule), @@ -68,7 +70,7 @@ namespace PackageName.CompanyName.ProjectName; typeof(AbpIdentitySessionAspNetCoreModule), typeof(AbpTelemetrySkyWalkingModule), typeof(AbpTelemetryOpenTelemetryModule), - typeof(AbpExporterMiniExcelModule), + typeof(AbpExporterMiniSoftwareModule), typeof(AbpClaimsMappingModule), typeof(AbpEmailingPlatformModule), typeof(AbpSmsPlatformModule), @@ -93,7 +95,7 @@ public partial class ProjectNameHttpApiHostModule : AbpModule var configuration = context.Services.GetConfiguration(); ConfigureWrapper(); - ConfigureMiniExcel(); + ConfigureMiniSoftware(); ConfigureExceptionHandling(); ConfigureVirtualFileSystem(); ConfigureTiming(configuration); diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/EnumDescriptionSchemaFilter.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/EnumDescriptionSchemaFilter.cs new file mode 100644 index 000000000..f7adfe64f --- /dev/null +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/EnumDescriptionSchemaFilter.cs @@ -0,0 +1,41 @@ +using Microsoft.OpenApi; +using System; +using System.ComponentModel; +using System.Reflection; + +namespace Swashbuckle.AspNetCore.SwaggerGen; + +#nullable enable +public class EnumDescriptionSchemaFilter : ISchemaFilter +{ + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) + { + if (context.Type.IsEnum) + { + var enumType = context.Type; + var enumValues = Enum.GetValues(enumType); + var underlyingType = Enum.GetUnderlyingType(enumType); + + var enumDesc = enumType.GetCustomAttribute()?.Description ?? enumType.Name; + schema.Description += $"{enumDesc}
"; + + schema.Description += "

Options:

    "; + + foreach (var value in enumValues) + { + string? description = default!; + var name = Enum.GetName(enumType, value); + if (name != null) + { + var memberInfo = enumType.GetMember(name)[0]; + description = memberInfo.GetCustomAttribute()?.Description ?? name; + } + var numericValue = Convert.ChangeType(value, underlyingType); + schema.Description += $"
  • {numericValue}: {name}({description ?? "No description."})
  • "; + } + + schema.Description += "
"; + } + } +} +#nullable disable diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/TenantHeaderParamter.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/TenantHeaderParamter.cs new file mode 100644 index 000000000..25809383e --- /dev/null +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Swashbuckle/AspNetCore/SwaggerGen/TenantHeaderParamter.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.Options; +using Microsoft.OpenApi; +using System.Collections.Generic; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.MultiTenancy; + +namespace Swashbuckle.AspNetCore.SwaggerGen; + +public class TenantHeaderParamter : IOperationFilter +{ + private readonly AbpMultiTenancyOptions _multiTenancyOptions; + private readonly AbpAspNetCoreMultiTenancyOptions _aspNetCoreMultiTenancyOptions; + public TenantHeaderParamter( + IOptions multiTenancyOptions, + IOptions aspNetCoreMultiTenancyOptions) + { + _multiTenancyOptions = multiTenancyOptions.Value; + _aspNetCoreMultiTenancyOptions = aspNetCoreMultiTenancyOptions.Value; + } + + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + if (_multiTenancyOptions.IsEnabled) + { + operation.Parameters ??= new List(); + operation.Parameters.Add(new OpenApiParameter + { + Name = _aspNetCoreMultiTenancyOptions.TenantKey, + In = ParameterLocation.Header, + Description = "Tenant Id in http header", + Required = false + }); + } + } +} diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs deleted file mode 100644 index e628695db..000000000 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; -using System.Collections.Generic; -using Volo.Abp.MultiTenancy; - -namespace PackageName.CompanyName.ProjectName; - -public class TenantHeaderParamter : IOperationFilter -{ - private readonly AbpMultiTenancyOptions _options; - public TenantHeaderParamter( - IOptions options) - { - _options = options.Value; - } - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - if (_options.IsEnabled) - { - operation.Parameters = operation.Parameters ?? new List(); - operation.Parameters.Add(new OpenApiParameter - { - Name = TenantResolverConsts.DefaultTenantKey, - In = ParameterLocation.Header, - Description = "Tenant Id/Name", - Required = false - }); - } - } -} diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json index 6ad910b64..0dacd0e61 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json @@ -83,6 +83,10 @@ } }, "RemoteServices": { + "BlobManagement": { + "BaseUrl": "http://127.0.0.1:30025", + "UseCurrentAccessToken": "true" + }, "Platform": { "BaseUrl": "http://127.0.0.1:30025", "UseCurrentAccessToken": "False" @@ -142,7 +146,8 @@ }, "AuthServer": { "Authority": "http://127.0.0.1:44385/", - "Audience": "lingyun-abp-application", + "Audience": "ProjectName", + "ValidAudiences": [ "lingyun-abp-application" ], "MapInboundClaims": false, "RequireHttpsMetadata": false, "SwaggerClientId": "vue-oauth-client" @@ -184,24 +189,23 @@ "Override": { "System": "Warning", "Microsoft": "Warning", + "Microsoft.EntityFrameworkCore": "Information", "DotNetCore": "Debug" } }, "WriteTo": [ { - "Name": "Console", - "Args": { - "restrictedToMinimumLevel": "Debug", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "Elasticsearch", + "Name": "Async", "Args": { - "nodeUris": "http://127.0.0.1:9200", - "indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}", - "autoRegisterTemplate": true, - "autoRegisterTemplateVersion": "ESv7" + "configure": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Debug", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] } } ] diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json index b50f377f8..89b10a062 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json @@ -1,6 +1,9 @@ { + "AntiForgery": { + "AutoValidate": false + }, "App": { - "CorsOrigins": "http://127.0.0.1:30000", + "CorsOrigins": ["http://127.0.0.1:30000"], "RefreshClaimsUrl": "http://127.0.0.1:30015/", "HealthChecks": "/healthz" }, @@ -35,72 +38,77 @@ "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ], "WriteTo": [ { - "Name": "Console", - "Args": { - "initialMinimumLevel": "Verbose", - "standardErrorFromLevel": "Verbose", - "restrictedToMinimumLevel": "Verbose", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "Logs/Debug-.log", - "restrictedToMinimumLevel": "Debug", - "rollingInterval": "Day", - "rollOnFileSizeLimit": true, - "retainedFileCountLimit": 50, - "fileSizeLimitBytes": 5242880, - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "Logs/Info-.log", - "restrictedToMinimumLevel": "Information", - "rollingInterval": "Day", - "rollOnFileSizeLimit": true, - "retainedFileCountLimit": 50, - "fileSizeLimitBytes": 5242880, - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "Logs/Warn-.log", - "restrictedToMinimumLevel": "Warning", - "rollingInterval": "Day", - "rollOnFileSizeLimit": true, - "retainedFileCountLimit": 50, - "fileSizeLimitBytes": 5242880, - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "Logs/Error-.log", - "restrictedToMinimumLevel": "Error", - "rollingInterval": "Day", - "rollOnFileSizeLimit": true, - "retainedFileCountLimit": 50, - "fileSizeLimitBytes": 5242880, - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "File", + "Name": "Async", "Args": { - "path": "Logs/Fatal-.log", - "restrictedToMinimumLevel": "Fatal", - "rollingInterval": "Day", - "rollOnFileSizeLimit": true, - "retainedFileCountLimit": 50, - "fileSizeLimitBytes": 5242880, - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + "configure": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Debug", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] } } ] diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore.csproj b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore.csproj index 1d4b91f98..3419cbb03 100644 --- a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore.csproj +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore.csproj @@ -5,9 +5,14 @@ net10.0 - enable - enable + PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore + PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore + false + false + false false + enable + PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore @@ -17,7 +22,7 @@
- + diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDataSeeder.cs b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDataSeeder.cs new file mode 100644 index 000000000..262264cc9 --- /dev/null +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDataSeeder.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +public class ProjectNameDataSeeder : ITransientDependency +{ + protected ILogger Logger { get; } + protected ICurrentTenant CurrentTenant { get; } + + public ProjectNameDataSeeder( + ICurrentTenant currentTenant) + { + CurrentTenant = currentTenant; + + Logger = NullLogger.Instance; + } + + public virtual Task SeedAsync(DataSeedContext context) + { + // TODO: 此处执行你的数据种子 + return Task.CompletedTask; + } +} diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationEventHandler.cs b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationEventHandler.cs index 74a4a39bc..7d762133e 100644 --- a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationEventHandler.cs +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationEventHandler.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Logging; -using System; using System.Threading.Tasks; using Volo.Abp.Data; using Volo.Abp.DistributedLocking; @@ -12,10 +11,10 @@ namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; public class ProjectNameDbMigrationEventHandler : EfCoreDatabaseMigrationEventHandlerBase { - protected IDataSeeder DataSeeder { get; } + protected ProjectNameDataSeeder DataSeeder { get; } public ProjectNameDbMigrationEventHandler( - IDataSeeder dataSeeder, + ProjectNameDataSeeder dataSeeder, ITenantStore tenantStore, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, @@ -29,8 +28,18 @@ public class ProjectNameDbMigrationEventHandler : EfCoreDatabaseMigrationEventHa DataSeeder = dataSeeder; } - protected async override Task SeedAsync(Guid? tenantId) + protected async override Task AfterTenantCreated(TenantCreatedEto eventData, bool schemaMigrated) { - await DataSeeder.SeedAsync(tenantId); + // 新租户数据种子 + var context = new DataSeedContext(eventData.Id); + if (eventData.Properties != null) + { + foreach (var property in eventData.Properties) + { + context.WithProperty(property.Key, property.Value); + } + } + + await DataSeeder.SeedAsync(context); } } diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationService.cs b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationService.cs index 86343cf1d..8a2076966 100644 --- a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationService.cs +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigrationService.cs @@ -1,9 +1,6 @@ using LINGYUN.Abp.Data.DbMigrator; -using LINGYUN.Abp.Saas.Tenants; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; @@ -16,14 +13,10 @@ namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; public class ProjectNameDbMigrationService : EfCoreRuntimeDbMigratorBase, ITransientDependency { - protected IDataSeeder DataSeeder { get; } - protected IDbSchemaMigrator DbSchemaMigrator { get; } - protected ITenantRepository TenantRepository { get; } + protected ProjectNameDataSeeder DataSeeder { get; } public ProjectNameDbMigrationService( - IDataSeeder dataSeeder, - IDbSchemaMigrator dbSchemaMigrator, - ITenantRepository tenantRepository, + ProjectNameDataSeeder dataSeeder, ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, IServiceProvider serviceProvider, @@ -35,36 +28,11 @@ public class ProjectNameDbMigrationService : EfCoreRuntimeDbMigratorBase tenants; - - try - { - tenants = await TenantRepository.GetListAsync(); - } - catch - { - return; - } - - - foreach (var tenant in tenants.Where(x => x.IsActive)) - { - await LockAndApplyDatabaseWithTenantMigrationsAsync(tenant.Id); - } } protected async override Task SeedAsync() { - Logger.LogInformation($"Executing {(!CurrentTenant.IsAvailable ? "host" : CurrentTenant.Name ?? CurrentTenant.GetId().ToString())} database seed..."); - - await DataSeeder.SeedAsync(CurrentTenant.Id); + // DbMigrator迁移数据种子 + await DataSeeder.SeedAsync(new DataSeedContext()); } } \ No newline at end of file diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs index 823981a7f..4e45b22f5 100644 --- a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs @@ -6,7 +6,9 @@ using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Modularity; #if MySQL -using Volo.Abp.EntityFrameworkCore.MySQL; +// using Volo.Abp.EntityFrameworkCore.MySQL; +using LINGYUN.Abp.EntityFrameworkCore.MySQL; +using Microsoft.EntityFrameworkCore; #elif SqlServer using Volo.Abp.EntityFrameworkCore.SqlServer; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -17,6 +19,7 @@ using Volo.Abp.EntityFrameworkCore.Oracle; #elif OracleDevart using Volo.Abp.EntityFrameworkCore.Oracle.Devart; #elif PostgreSql +using System; using Volo.Abp.EntityFrameworkCore.PostgreSql; #endif @@ -27,7 +30,8 @@ namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; typeof(ProjectNameEntityFrameworkCoreModule), typeof(AbpSaasEntityFrameworkCoreModule), #if MySQL - typeof(AbpEntityFrameworkCoreMySQLPomeloModule), + // typeof(AbpEntityFrameworkCoreMySQLPomeloModule), + typeof(AbpEntityFrameworkCoreMySQLMicrotingModule), #elif SqlServer typeof(AbpEntityFrameworkCoreSqlServerModule), #elif Sqlite @@ -43,6 +47,13 @@ namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; )] public class ProjectNameDbMigratorEntityFrameworkCoreModule : AbpModule { +#if PostgreSql + public override void PreConfigureServices(ServiceConfigurationContext context) + { + // https://www.npgsql.org/efcore/release-notes/6.0.html#opting-out-of-the-new-timestamp-mapping-logic + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); + } +#endif public override void ConfigureServices(ServiceConfigurationContext context) { // 配置Ef @@ -52,12 +63,12 @@ public class ProjectNameDbMigratorEntityFrameworkCoreModule : AbpModule options.UseMySQL(mysql => { // see: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1960 - mysql.TranslateParameterizedCollectionsToConstants(); + mysql.UseParameterizedCollectionMode(ParameterTranslationMode.Constant); }); options.UseMySQL(mysql => { // see: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1960 - mysql.TranslateParameterizedCollectionsToConstants(); + mysql.UseParameterizedCollectionMode(ParameterTranslationMode.Constant); }); #elif SqlServer options.UseSqlServer(); diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json index 331b315cc..4d72e2c6a 100644 --- a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json @@ -1,13 +1,6 @@ { "ConnectionStrings": { - "ProjectName": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpSaas": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpTenantManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpSettingManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpPermissionManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpFeatureManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpTextTemplating": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", - "AbpLocalizationManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + "ProjectName": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" }, "DistributedLock": { "IsEnabled": true, diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs deleted file mode 100644 index 0ace9b456..000000000 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs +++ /dev/null @@ -1,10 +0,0 @@ -using AutoMapper; - -namespace PackageName.CompanyName.ProjectName; - -public class ProjectNameApplicationMapperProfile : Profile -{ - public ProjectNameApplicationMapperProfile() - { - } -} diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMappers.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMappers.cs new file mode 100644 index 000000000..33957dbb9 --- /dev/null +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMappers.cs @@ -0,0 +1,15 @@ +using Riok.Mapperly.Abstractions; +using Volo.Abp.Mapperly; +using Volo.Abp.ObjectExtending; + +namespace PackageName.CompanyName.ProjectName; + +// Mapper Exemple + +//[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)] +//[MapExtraProperties(DefinitionChecks = MappingPropertyDefinitionChecks.None)] +//public partial class EntityToEntityDtoMapper : MapperBase +//{ +// public override partial DentityDto Map(Entity source); +// public override partial void Map(Entity source, DentityDto destination); +//} diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs index 164310d8c..6af4fc0fe 100644 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs @@ -3,7 +3,6 @@ using LINGYUN.Abp.Exporter; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Application; using Volo.Abp.Authorization; -using Volo.Abp.AutoMapper; using Volo.Abp.Modularity; namespace PackageName.CompanyName.ProjectName; @@ -19,11 +18,6 @@ public class ProjectNameApplicationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAutoMapperObjectMapper(); - - Configure(options => - { - options.AddProfile(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); } } diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj index b09e592a6..c98b69e4e 100644 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj @@ -15,9 +15,9 @@
- + diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameBasicRepository.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameBasicRepository.cs index 290e09398..7b26a6577 100644 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameBasicRepository.cs +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameBasicRepository.cs @@ -1,17 +1,17 @@ -using LINGYUN.Abp.DataProtection; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Specifications; namespace PackageName.CompanyName.ProjectName; /// -/// 基本仓储接口 +/// 实体仓储接口 /// /// 实体类型 /// 实体主键类型 -public interface IProjectNameBasicRepository : IDataProtectionRepository +public interface IProjectNameBasicRepository : IBasicRepository where TEntity : class, IEntity { /// @@ -34,21 +34,8 @@ public interface IProjectNameBasicRepository : IDataProtectionRep /// Task> GetListAsync( ISpecification specification, - string sorting = nameof(IEntity.Id), + string? sorting = nameof(IEntity.Id), int maxResultCount = 10, int skipCount = 0, CancellationToken cancellationToken = default); - /// - /// 获取过滤后的实体列表 - /// - /// - /// - /// - /// - /// - Task> GetListAsync( - ISpecification specification, - string sorting = nameof(IEntity.Id), - int maxResultCount = 10, - CancellationToken cancellationToken = default); } diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameDataProtectionRepository.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameDataProtectionRepository.cs new file mode 100644 index 000000000..d59fdce60 --- /dev/null +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameDataProtectionRepository.cs @@ -0,0 +1,15 @@ +using LINGYUN.Abp.DataProtection; +using Volo.Abp.Domain.Entities; + +namespace PackageName.CompanyName.ProjectName; +/// +/// 受保护实体保护仓储接口 +/// +/// 实体类型 +/// 实体主键类型 +public interface IProjectNameDataProtectionRepository : + IProjectNameBasicRepository, + IDataProtectionRepository + where TEntity : class, IEntity +{ +} diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDataSeedContributor.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDataSeedContributor.cs deleted file mode 100644 index 4e70f3739..000000000 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDataSeedContributor.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; - -namespace PackageName.CompanyName.ProjectName; - -public class ProjectNameDataSeedContributor : IDataSeedContributor, ITransientDependency -{ - private readonly ILogger _logger; - public ProjectNameDataSeedContributor(ILogger logger) - { - _logger = logger; - } - - public Task SeedAsync(DataSeedContext context) - { - _logger.LogInformation("Write your data seed logic here."); - - return Task.CompletedTask; - } -} diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs deleted file mode 100644 index 79c7af553..000000000 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs +++ /dev/null @@ -1,11 +0,0 @@ -using AutoMapper; - -namespace PackageName.CompanyName.ProjectName; - -public class ProjectNameDomainMapperProfile : Profile -{ - public ProjectNameDomainMapperProfile() - { - - } -} diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMappers.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMappers.cs new file mode 100644 index 000000000..b18d57ea8 --- /dev/null +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMappers.cs @@ -0,0 +1,16 @@ +using Riok.Mapperly.Abstractions; +using Volo.Abp.Mapperly; +using Volo.Abp.ObjectExtending; + +namespace PackageName.CompanyName.ProjectName; + +// Mapper Exemple + +//[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)] +//[MapExtraProperties(DefinitionChecks = MappingPropertyDefinitionChecks.None)] +//public partial class EntityToEntityEtoMapper : MapperBase +//{ +// public override partial DentityEto Map(Entity source); +// public override partial void Map(Entity source, DentityEto destination); +//} + diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs index 2aca6020d..dc7883264 100644 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs @@ -1,14 +1,14 @@ using LINGYUN.Abp.DataProtection; using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AutoMapper; using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.Threading; namespace PackageName.CompanyName.ProjectName; [DependsOn( - typeof(AbpAutoMapperModule), + typeof(AbpMapperlyModule), typeof(AbpDataProtectionModule), typeof(ProjectNameDomainSharedModule))] public class ProjectNameDomainModule : AbpModule @@ -16,15 +16,13 @@ public class ProjectNameDomainModule : AbpModule private static readonly OneTimeRunner OneTimeRunner = new(); public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAutoMapperObjectMapper(); - - Configure(options => - { - options.AddProfile(validate: true); - }); + context.Services.AddMapperlyObjectMapper(); Configure(options => { + // options.AutoEventSelectors.Add(); + + // options.EtoMappings.Add(); }); } diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameBasicRepository.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameBasicRepository.cs new file mode 100644 index 000000000..9b0d2cf92 --- /dev/null +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameBasicRepository.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Specifications; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +public abstract class EfCoreProjectNameBasicRepository : + EfCoreRepository, + IProjectNameBasicRepository + where TEntity : class, IEntity +{ + protected EfCoreProjectNameBasicRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async virtual Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync()) + .Where(specification.ToExpression()) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListAsync( + ISpecification specification, + string? sorting = nameof(IEntity.Id), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync()) + .Where(specification.ToExpression()) + .OrderBy(GetSortingOrDefault(sorting)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + protected virtual string GetSortingOrDefault(string? sorting = nameof(IEntity.Id)) + { + if (sorting.IsNullOrWhiteSpace()) + { + return nameof(IEntity.Id); + } + return sorting; + } +} diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameRepository.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameDataProtectionRepository.cs similarity index 73% rename from aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameRepository.cs rename to aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameDataProtectionRepository.cs index 6ca9a0a89..bfdeb6aab 100644 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameRepository.cs +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreProjectNameDataProtectionRepository.cs @@ -18,13 +18,13 @@ namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; /// 实体类型 /// 实体主键类型 /// 实体数据权限类型/typeparam> -public abstract class EfCoreProjectNameRepository : +public abstract class EfCoreProjectNameDataProtectionRepository : EfCoreDataProtectionRepository, - IProjectNameBasicRepository + IProjectNameDataProtectionRepository where TEntity : class, IEntity, IDataProtected where TEntityAuth : DataAuthBase { - protected EfCoreProjectNameRepository( + protected EfCoreProjectNameDataProtectionRepository( IDbContextProvider dbContextProvider, IDataAuthorizationService dataAuthorizationService, IEntityTypeFilterBuilder entityTypeFilterBuilder, @@ -44,7 +44,7 @@ public abstract class EfCoreProjectNameRepository : public async virtual Task> GetListAsync( ISpecification specification, - string sorting = nameof(IEntity.Id), + string? sorting = nameof(IEntity.Id), int maxResultCount = 10, int skipCount = 0, CancellationToken cancellationToken = default) @@ -56,20 +56,7 @@ public abstract class EfCoreProjectNameRepository : .ToListAsync(GetCancellationToken(cancellationToken)); } - public async virtual Task> GetListAsync( - ISpecification specification, - string sorting = nameof(IEntity.Id), - int maxResultCount = 10, - CancellationToken cancellationToken = default) - { - return await (await GetQueryableAsync()) - .Where(specification.ToExpression()) - .OrderBy(GetSortingOrDefault(sorting)) - .Take(maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); - } - - protected virtual string GetSortingOrDefault(string sorting = nameof(IEntity.Id)) + protected virtual string GetSortingOrDefault(string? sorting = nameof(IEntity.Id)) { if (sorting.IsNullOrWhiteSpace()) { diff --git a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs index 45a52fd3f..3e1b6a4b2 100644 --- a/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs +++ b/aspnet-core/templates/micro/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs @@ -1,5 +1,6 @@ using LINGYUN.Abp.DataProtection.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.EntityFrameworkCore.DependencyInjection; using Volo.Abp.Modularity; namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; @@ -15,5 +16,14 @@ public class ProjectNameEntityFrameworkCoreModule : AbpModule { options.AddDefaultRepositories(); }); + + Configure(options => + { + // Default Entity Details Func + //options.Entity(e => + //{ + // e.DefaultWithDetailsFunc = x => x; + //}); + }); } } diff --git a/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj b/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj index 31c55796f..a1ce5070d 100644 --- a/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj +++ b/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj @@ -1,18 +1,18 @@ - - net10.0 - - false - + + net10.0 + + false + - - - + + + - - - - + + + + diff --git a/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj b/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj index 3ab8047d1..0cec08c93 100644 --- a/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj +++ b/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj @@ -1,18 +1,18 @@ - - net10.0 - - false - + + net10.0 + + false + - - - + + + - - - - + + + + diff --git a/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj b/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj index af08cb5ca..1ab84ca53 100644 --- a/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj +++ b/aspnet-core/templates/micro/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj @@ -1,23 +1,23 @@ - - net10.0 - - false - + + net10.0 + + false + - - - - - - - - - - - - - + + + + + + + + + + + + + From 841afd2ebfbaed8f00d1cfd5457d8452252c69a6 Mon Sep 17 00:00:00 2001 From: dongfo <630024306@qq.com> Date: Tue, 12 May 2026 15:55:52 +0800 Subject: [PATCH 04/40] Fix delay handling in EnqueueAsync method Updated EnqueueAsync method to handle delay correctly by using BeginTime instead of interval. This prevents immediate execution of jobs with longer delay durations. --- .../BackgroundTasks/BackgroundJobManager.cs | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs index edc460e4e..ded32941d 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN/Abp/BackgroundTasks/BackgroundJobManager.cs @@ -47,33 +47,36 @@ public class BackgroundJobManager : IBackgroundJobManager TimeSpan? delay = null) { var jobConfiguration = Options.GetJob(); - var interval = 0; - if (delay.HasValue) - { - interval = delay.Value.Seconds; - } - var jobId = GuidGenerator.Create(); - var jobArgs = new Dictionary - { - { nameof(TArgs), JsonSerializer.Serialize(args) }, - { "ArgsType", jobConfiguration.ArgsType.AssemblyQualifiedName }, - { "JobType", jobConfiguration.JobType.AssemblyQualifiedName }, - { "JobName", jobConfiguration.JobName }, - }; - var jobInfo = new JobInfo - { - Id = jobId.ToString(), - TenantId = CurrentTenant.Id, - Name = jobId.ToString(), - Group = "BackgroundJobs", - Priority = ConverForm(priority), - Source = JobSource.System, - BeginTime = DateTime.Now, - Args = jobArgs, - Description = "From the framework background jobs", - JobType = JobType.Once, - Interval = interval, - CreationTime = Clock.Now, + // 用 BeginTime 表达延迟启动,避免与 JobInfo.Interval(重复间隔)语义混用。 + // 原实现使用 delay.Value.Seconds(仅取秒分量 0-59), + // 会让 TimeSpan.FromMinutes(5) 这类整分钟/整小时的延迟退化为 0,导致任务立即执行。 + var now = Clock.Now; + var beginTime = now; + if (delay.HasValue && delay.Value > TimeSpan.Zero) + { + beginTime = now.Add(delay.Value); + } + var jobId = GuidGenerator.Create(); + var jobArgs = new Dictionary + { + { nameof(TArgs), JsonSerializer.Serialize(args) }, + { "ArgsType", jobConfiguration.ArgsType.AssemblyQualifiedName }, + { "JobType", jobConfiguration.JobType.AssemblyQualifiedName }, + { "JobName", jobConfiguration.JobName }, + }; + var jobInfo = new JobInfo + { + Id = jobId.ToString(), + TenantId = CurrentTenant.Id, + Name = jobId.ToString(), + Group = "BackgroundJobs", + Priority = ConverForm(priority), + Source = JobSource.System, + BeginTime = beginTime, + Args = jobArgs, + Description = "From the framework background jobs", + JobType = JobType.Once, + CreationTime = now, // 确保不会被轮询入队 Status = JobStatus.None, NodeName = TasksOptions.NodeName, From 124281dc786de8d98d279ac13f99c0f570034328 Mon Sep 17 00:00:00 2001 From: dongfo <630024306@qq.com> Date: Tue, 12 May 2026 15:57:46 +0800 Subject: [PATCH 05/40] Update QuartzJobCreator.cs --- .../Quartz/QuartzJobCreator.cs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobCreator.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobCreator.cs index 91e40d67b..43f82c739 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobCreator.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN/Abp/BackgroundTasks/Quartz/QuartzJobCreator.cs @@ -125,11 +125,21 @@ public class QuartzJobCreator : IQuartzJobCreator, ISingletonDependency triggerBuilder .WithIdentity(KeyBuilder.CreateTriggerKey(job)) .WithDescription(job.Description) - .StartAt(Clock.Now.AddSeconds(job.Interval)) .EndAt(job.EndTime) .ForJob(KeyBuilder.CreateJobKey(job)) .WithPriority((int)job.Priority); - + + // 首次启动时间由 BeginTime 决定,不再使用 Interval 作为"延迟启动"。 + // Interval 仅在 Persistent 周期任务中表示"重复间隔"。 + if (job.BeginTime > Clock.Now) + { + triggerBuilder.StartAt(job.BeginTime); + } + else + { + triggerBuilder.StartNow(); + } + // Quartz约定. 重复间隔不能为0 // fix throw Quartz.SchedulerException: Repeat Interval cannot be zero. var scheduleBuilder = SimpleScheduleBuilder.Create(); @@ -139,14 +149,8 @@ public class QuartzJobCreator : IQuartzJobCreator, ISingletonDependency { scheduleBuilder.WithRepeatCount(maxCount); } - if (job.Interval > 0) - { - scheduleBuilder.WithIntervalInSeconds(job.Interval); - } - else - { - scheduleBuilder.WithIntervalInSeconds(300); - } + scheduleBuilder.WithIntervalInSeconds(job.Interval > 0 ? job.Interval : 300); + triggerBuilder.WithSchedule(scheduleBuilder); From f99cf575014d5c1510bf0bed880115c9295aa212 Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 18 May 2026 13:53:30 +0800 Subject: [PATCH 06/40] feat: Add calendar module --- aspnet-core/LINGYUN.MicroService.Aspire.slnx | 3 + .../LINGYUN.Abp.Calendar/FodyWeavers.xml | 3 + .../LINGYUN.Abp.Calendar.csproj | 21 ++++ .../LINGYUN/Abp/Calendar/AbpCalendarModule.cs | 9 ++ .../Abp/Calendar/AbpCalendarOptions.cs | 40 ++++++ .../Abp/Calendar/IWorkdayCalendarService.cs | 24 ++++ .../Abp/Calendar/IWorkdayCalendarStore.cs | 18 +++ .../Abp/Calendar/NullWorkdayCalendarStore.cs | 19 +++ .../LINGYUN/Abp/Calendar/SpecialDateInfo.cs | 21 ++++ .../LINGYUN/Abp/Calendar/SpecialDateType.cs | 24 ++++ .../LINGYUN/Abp/Calendar/WorkTimeRange.cs | 27 ++++ .../Abp/Calendar/WorkdayCalendarInfo.cs | 34 +++++ .../Abp/Calendar/WorkdayCalendarService.cs | 117 ++++++++++++++++++ .../calendars/LINGYUN.Abp.Calendar/README.md | 15 +++ 14 files changed, 375 insertions(+) create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md diff --git a/aspnet-core/LINGYUN.MicroService.Aspire.slnx b/aspnet-core/LINGYUN.MicroService.Aspire.slnx index 166412f51..a19022d70 100644 --- a/aspnet-core/LINGYUN.MicroService.Aspire.slnx +++ b/aspnet-core/LINGYUN.MicroService.Aspire.slnx @@ -90,6 +90,9 @@ + + + diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj new file mode 100644 index 000000000..489ab7fe2 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj @@ -0,0 +1,21 @@ + + + + + + + net8.0;net9.0;net10.0 + LINGYUN.Abp.WorkdayCalendar + LINGYUN.Abp.WorkdayCalendar + false + false + false + enable + + + + + + + + diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs new file mode 100644 index 000000000..a52b9aadf --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Modularity; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.Calendar; + +[DependsOn(typeof(AbpTimingModule))] +public class AbpCalendarModule : AbpModule +{ +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs new file mode 100644 index 000000000..a4f0278d9 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs @@ -0,0 +1,40 @@ +using System; + +namespace LINGYUN.Abp.Calendar; + +public class AbpCalendarOptions +{ + /// + /// 默认工作日范围 + /// 默认: 周一到周五 + /// + public DayOfWeek[] DefaultWorkdays { get; set; } + /// + /// 是否启用工作时间限制 + /// 默认: true + /// + public bool EnableWorkTimeRestriction { get; set; } + /// + /// 默认工作时间范围 + /// 默认: 09:00-12:00、13:00-18:00 + /// + public WorkTimeRange[] DefaultWorkTimes { get; set; } + + public AbpCalendarOptions() + { + DefaultWorkdays = new[] + { + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday + }; + EnableWorkTimeRestriction = true; + DefaultWorkTimes = new[] + { + new WorkTimeRange(new TimeSpan(9, 0, 0), new TimeSpan(12, 0, 0)), + new WorkTimeRange(new TimeSpan(13, 0, 0), new TimeSpan(18, 0, 0)), + }; + } +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs new file mode 100644 index 000000000..0e5d0c796 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Calendar; + +public interface IWorkdayCalendarService +{ + /// + /// 检查指定时间是否在工作日 + /// + Task IsWorkdayAsync(DateOnly date); + /// + /// 检查指定时间是否在工作时间 + /// + /// + /// + Task IsInWorkTimeAsync(DateTime dateTime); + /// + /// 获取下一个工作日 + /// + /// + /// + Task GetNextWorkdayAsync(DateOnly date); +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs new file mode 100644 index 000000000..202239c17 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Calendar; + +public interface IWorkdayCalendarStore +{ + /// + /// 获取特殊日期 + /// + /// 日期 + /// + Task FindSpecialDateAsync(DateOnly date); + /// + /// 获取默认工作日历 + /// + Task FindDefaultCalendarAsync(); +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs new file mode 100644 index 000000000..2ddbb9f63 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Calendar; + +[Dependency(TryRegister = true)] +public class NullWorkdayCalendarStore : IWorkdayCalendarStore, ISingletonDependency +{ + public Task FindDefaultCalendarAsync() + { + return Task.FromResult(null); + } + + public Task FindSpecialDateAsync(DateOnly date) + { + return Task.FromResult(null); + } +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs new file mode 100644 index 000000000..686a90b7e --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs @@ -0,0 +1,21 @@ +using System; + +namespace LINGYUN.Abp.Calendar; +/// +/// 特殊日期 +/// +public class SpecialDateInfo +{ + /// + /// 日期 + /// + public DateOnly Date { get; set; } + /// + /// 特殊日期类型 + /// + public SpecialDateType Type { get; set; } + /// + /// 特殊日期描述 + /// + public string? Description { get; set; } +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs new file mode 100644 index 000000000..3b034a423 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; + +namespace LINGYUN.Abp.Calendar; +/// +/// 特殊日期类型 +/// +public enum SpecialDateType +{ + /// + /// 法定节假日 + /// + [Description("法定节假日")] + Holiday = 0, + /// + /// 特殊工作日 + /// + [Description("特殊工作日")] + SpecialWorkday = 1, + /// + /// 自定义假期 + /// + [Description("自定义假期")] + CustomHoliday = 2 +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs new file mode 100644 index 000000000..0ec86ab9a --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs @@ -0,0 +1,27 @@ +using System; + +namespace LINGYUN.Abp.Calendar; +/// +/// 工作时间范围 +/// +public class WorkTimeRange +{ + /// + /// 开始时间 + /// + public TimeSpan StartTime { get; set; } + /// + /// 截止时间 + /// + public TimeSpan EndTime { get; set; } + public WorkTimeRange() + { + + } + + public WorkTimeRange(TimeSpan startTime, TimeSpan endTime) + { + StartTime = startTime; + EndTime = endTime; + } +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs new file mode 100644 index 000000000..07ab09520 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs @@ -0,0 +1,34 @@ +using System; + +namespace LINGYUN.Abp.Calendar; + +/// +/// 工作日历信息 +/// +public class WorkdayCalendarInfo +{ + /// + /// 日历名称 + /// + public string Name { get; set; } + /// + /// 默认日历 + /// + public bool IsDefault { get; set; } + /// + /// 工作日范围 + /// + public DayOfWeek[] Workdays { get; set; } + /// + /// 工作时间范围 + /// + public WorkTimeRange[]? WorkTimes { get; set; } + /// + /// 是否启用工作时间限制 + /// + public bool EnableWorkTimeRestriction { get; set; } + /// + /// 特殊日期列表 + /// + public SpecialDateInfo[]? SpecialDates { get; set; } +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs new file mode 100644 index 000000000..e63ff3150 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs @@ -0,0 +1,117 @@ +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Calendar; + +public class WorkdayCalendarService : IWorkdayCalendarService, ITransientDependency +{ + private readonly AbpCalendarOptions _options; + private readonly IWorkdayCalendarStore _workdayCalendarStore; + + public WorkdayCalendarService( + IOptions options, + IWorkdayCalendarStore workdayCalendarStore) + { + _options = options.Value; + _workdayCalendarStore = workdayCalendarStore; + } + + public async virtual Task GetNextWorkdayAsync(DateOnly date) + { + var nextDay = date.AddDays(1); + // 以31天为限 + var maxAttempts = 30; + + for (var i = 0; i < maxAttempts; i++) + { + if (await IsWorkdayAsync(nextDay)) + { + return nextDay; + } + nextDay = nextDay.AddDays(1); + } + + // 如果30天内都找不到工作日,返回原日期+1天 + return date.AddDays(1); + } + + public async virtual Task IsWorkdayAsync(DateOnly date) + { + // 特殊工作日定义 + var specialDate = await _workdayCalendarStore.FindSpecialDateAsync(date); + if (specialDate != null) + { + return specialDate.Type == SpecialDateType.SpecialWorkday; + } + // 获取默认工作日历定义 + var calendar = await _workdayCalendarStore.FindDefaultCalendarAsync(); + if (calendar == null) + { + // 未定义默认工作日历, 获取系统定义工作日范围 + return _options.DefaultWorkdays.Contains(date.DayOfWeek); + } + // 特殊工作日范围 + if (calendar.SpecialDates != null && + calendar.SpecialDates.Any(x => x.Date == date && x.Type == SpecialDateType.SpecialWorkday)) + { + return true; + } + // 工作日范围 + if (!calendar.Workdays.Contains(date.DayOfWeek)) + { + return false; + } + + return false; + } + + public async virtual Task IsInWorkTimeAsync(DateTime time) + { + var nowDate = DateOnly.FromDateTime(time); + // 特殊工作日定义 + var specialDate = await _workdayCalendarStore.FindSpecialDateAsync(nowDate); + if (specialDate != null) + { + return specialDate.Type == SpecialDateType.SpecialWorkday; + } + // 获取默认工作日历定义 + var calendar = await _workdayCalendarStore.FindDefaultCalendarAsync(); + if (calendar == null) + { + // 未定义默认工作日历, 获取系统定义工作日范围 + if (!_options.DefaultWorkdays.Contains(nowDate.DayOfWeek)) + { + return false; + } + if (_options.EnableWorkTimeRestriction && + !_options.DefaultWorkTimes.Any(timeRange => timeRange.StartTime >= time.TimeOfDay && timeRange.EndTime <= time.TimeOfDay)) + { + return false; + } + + return true; + } + // 特殊工作日范围 + if (calendar.SpecialDates != null && + calendar.SpecialDates.Any(x => x.Date == nowDate && x.Type == SpecialDateType.SpecialWorkday)) + { + return true; + } + // 工作日范围 + if (!calendar.Workdays.Contains(nowDate.DayOfWeek)) + { + return false; + } + // 工作时间范围 + if (calendar.EnableWorkTimeRestriction && + calendar.WorkTimes != null) + { + return calendar.WorkTimes.Any(x => x.StartTime >= time.TimeOfDay && x.EndTime <= time.TimeOfDay); + } + + return false; + } +} diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md new file mode 100644 index 000000000..3bb94652b --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md @@ -0,0 +1,15 @@ +# LINGYUN.Abp.Calendar + +日历模块, 定义系统日历参数, 用于特定场景. + +#### 注意 + + +## 功能特性 + + +## 配置使用 + + +## 更多信息 + From e68dea143e1cb93c7c46111fcbe3b06f76b1dfab Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 18 May 2026 13:57:16 +0800 Subject: [PATCH 07/40] feat: Add notification publish interceptor --- .../INotificationPublishInterceptor.cs | 20 +++++ .../NotificationPublishProvider.cs | 77 ++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs new file mode 100644 index 000000000..27437a1b5 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications; +/// +/// 通知发布拦截器, 实现此接口来增加发布前的自定义检查 +/// +public interface INotificationPublishInterceptor +{ + /// + /// 拦截优先级,数值越小优先级越高 + /// + int Priority { get; } + + /// + /// 在通知发布前执行检查 + /// + /// 通知信息 + /// true-允许发布, false-阻止发布 + Task CanPublishAsync(NotificationInfo notification); +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs index 8bf1cc899..8e52907a7 100644 --- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs @@ -1,6 +1,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -21,6 +23,11 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider public ICancellationTokenProvider CancellationTokenProvider => ServiceProvider.LazyGetService(NullCancellationTokenProvider.Instance); + private IEnumerable _interceptors; + protected IEnumerable Interceptors => + _interceptors ??= ServiceProvider.LazyGetService>() + ?? Enumerable.Empty(); + public async virtual Task CanPublishAsync(NotificationInfo notification) { return await CanPublishAsync(notification, GetCancellationToken()); @@ -28,9 +35,23 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider public async Task PublishAsync(NotificationPublishContext context) { - await PublishAsync(context, GetCancellationToken()); + var cancellationToken = GetCancellationToken(); + + // 通知拦截器检查 + if (!await ExecuteInterceptorsAsync(context, cancellationToken)) + { + return; + } + + await PublishAsync(context, cancellationToken); } + /// + /// 是否允许发布通知 + /// + /// + /// + /// protected virtual Task CanPublishAsync( NotificationInfo notification, CancellationToken cancellationToken = default) @@ -38,6 +59,60 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider return Task.FromResult(true); } + /// + /// 执行通知发布拦截器 + /// + /// + /// + /// + protected virtual async Task ExecuteInterceptorsAsync( + NotificationPublishContext context, + CancellationToken cancellationToken = default) + { + if (context.Notification.Type == NotificationType.System || + context.Notification.Type == NotificationType.ServiceCallback) + { + Logger.LogDebug( + "System or service callback notification {NotificationName}, skip all interceptors.", + context.Notification.Name); + return true; + } + + if (!Interceptors.Any()) + { + Logger.LogDebug("No notification publishing interceptors have been registered."); + return true; + } + + var orderedInterceptors = Interceptors.OrderBy(i => i.Priority); + + foreach (var interceptor in orderedInterceptors) + { + try + { + if (!await interceptor.CanPublishAsync(context.Notification)) + { + var reason = string.Format("The interceptor {0} prevented the publication of the notification {1}.", + interceptor.GetType().Name, + context.Notification.Name); + + context.Cancel(reason); + + Logger.LogWarning(reason); + return false; + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, + "An exception occurred while executing the interceptor {InterceptorType}. By default, publication is allowed.", + interceptor.GetType().Name); + } + } + + return true; + } + protected virtual CancellationToken GetCancellationToken(CancellationToken cancellationToken = default) { return CancellationTokenProvider.FallbackToProvider(cancellationToken); From 24dad660f8835a785559952822578cf22a9d444e Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 18 May 2026 13:57:58 +0800 Subject: [PATCH 08/40] feat: Implement the notification workday check interceptor --- aspnet-core/LINGYUN.MicroService.Aspire.slnx | 1 + .../FodyWeavers.xml | 3 + .../LINGYUN.Abp.Notifications.Calendar.csproj | 22 +++++++ .../AbpNotificationsCalendarModule.cs | 16 +++++ .../WorkdayCalendarPublishInterceptor.cs | 66 +++++++++++++++++++ .../README.md | 15 +++++ 6 files changed, 123 insertions(+) create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xml create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/AbpNotificationsCalendarModule.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/README.md diff --git a/aspnet-core/LINGYUN.MicroService.Aspire.slnx b/aspnet-core/LINGYUN.MicroService.Aspire.slnx index a19022d70..f44c32ec2 100644 --- a/aspnet-core/LINGYUN.MicroService.Aspire.slnx +++ b/aspnet-core/LINGYUN.MicroService.Aspire.slnx @@ -448,6 +448,7 @@ + diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xml b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj new file mode 100644 index 000000000..3715f079e --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj @@ -0,0 +1,22 @@ + + + + + + + net10.0 + LINGYUN.Abp.Notifications.Calendar + LINGYUN.Abp.Notifications.Calendar + false + false + false + enable + + + + + + + + + diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/AbpNotificationsCalendarModule.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/AbpNotificationsCalendarModule.cs new file mode 100644 index 000000000..781030660 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/AbpNotificationsCalendarModule.cs @@ -0,0 +1,16 @@ +using LINGYUN.Abp.Calendar; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.Calendar; + +[DependsOn( + typeof(AbpNotificationsModule), + typeof(AbpCalendarModule))] +public class AbpNotificationsCalendarModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddTransient(); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs new file mode 100644 index 000000000..a24d997bd --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs @@ -0,0 +1,66 @@ +using LINGYUN.Abp.Calendar; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.Notifications.Calendar; + +/// +/// 工作日通知发布拦截器 +/// +public class WorkdayCalendarPublishInterceptor : INotificationPublishInterceptor, ITransientDependency +{ + private readonly IClock _clock; + private readonly ICurrentTenant _currentTenant; + private readonly IWorkdayCalendarService _workdayCalendarService; + public ILogger Logger { protected get; set; } + + public WorkdayCalendarPublishInterceptor( + IClock clock, + ICurrentTenant currentTenant, + IWorkdayCalendarService workdayCalendarService) + { + _clock = clock; + _currentTenant = currentTenant; + _workdayCalendarService = workdayCalendarService; + + Logger = NullLogger.Instance; + } + + public int Priority => 100; + + public async Task CanPublishAsync(NotificationInfo notification) + { + try + { + using (_currentTenant.Change(notification.TenantId)) + { + var isWorktime = await _workdayCalendarService.IsInWorkTimeAsync(_clock.Now); + + if (!isWorktime) + { + Logger.LogInformation( + "Notification {NotificationName} was blocked during the working time check. Type: {NotificationType}, Time: {Time}.", + notification.Name, + notification.Type, + _clock.Now.ToString("yyyy-MM-dd HH:mm:ss")); + return false; + } + + return true; + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, + "If an abnormality occurs during the working day check, the default setting allows {NotificationName} to be notified to publish.", + notification.Name); + + return true; + } + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/README.md b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/README.md new file mode 100644 index 000000000..8695a85e8 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/README.md @@ -0,0 +1,15 @@ +# LINGYUN.Abp.Notifications.Calendar + +通知发布提供程序的工作日检查拦截器, 非系统定义工作日时不发布通知. + +#### 注意 + + +## 功能特性 + + +## 配置使用 + + +## 更多信息 + From 978a524a995d41866069f1d240034dd0bacb755c Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 18 May 2026 14:22:45 +0800 Subject: [PATCH 09/40] feat: Add the dependency of the notification workday interceptor module --- aspnet-core/LINGYUN.MicroService.All.slnx | 4 ++++ aspnet-core/LINGYUN.MicroService.SingleProject.slnx | 4 ++++ .../LINGYUN.Abp.MicroService.MessageService.csproj | 1 + .../MessageServiceModule.cs | 2 ++ .../LINGYUN/Abp/Calendar/WorkdayCalendarService.cs | 4 ++-- .../Calendar/WorkdayCalendarPublishInterceptor.cs | 3 +-- .../LY.MicroService.Applications.Single.csproj | 1 + .../MicroServiceApplicationsSingleModule.cs | 3 +++ .../LY.MicroService.RealtimeMessage.HttpApi.Host.csproj | 1 + .../RealtimeMessageHttpApiHostModule.cs | 2 ++ 10 files changed, 21 insertions(+), 4 deletions(-) diff --git a/aspnet-core/LINGYUN.MicroService.All.slnx b/aspnet-core/LINGYUN.MicroService.All.slnx index 011923378..a990dac8d 100644 --- a/aspnet-core/LINGYUN.MicroService.All.slnx +++ b/aspnet-core/LINGYUN.MicroService.All.slnx @@ -105,6 +105,9 @@ + + + @@ -433,6 +436,7 @@ + diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.slnx b/aspnet-core/LINGYUN.MicroService.SingleProject.slnx index 269419841..7f687aba2 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.slnx +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.slnx @@ -36,6 +36,9 @@ + + + @@ -96,6 +99,7 @@ + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/LINGYUN.Abp.MicroService.MessageService.csproj b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/LINGYUN.Abp.MicroService.MessageService.csproj index c266d7bb7..d56ea12ac 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/LINGYUN.Abp.MicroService.MessageService.csproj +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/LINGYUN.Abp.MicroService.MessageService.csproj @@ -55,6 +55,7 @@ + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MessageServiceModule.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MessageServiceModule.cs index 5445db5cd..4bc4d45f3 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MessageServiceModule.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MessageServiceModule.cs @@ -23,6 +23,7 @@ using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.MessageService; using LINGYUN.Abp.MessageService.EntityFrameworkCore; using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.Notifications.Calendar; using LINGYUN.Abp.Notifications.Common; using LINGYUN.Abp.Notifications.Emailing; using LINGYUN.Abp.Notifications.EntityFrameworkCore; @@ -102,6 +103,7 @@ namespace LINGYUN.Abp.MicroService.MessageService; typeof(AbpNotificationsWeChatWorkModule), typeof(AbpNotificationsExceptionHandlingModule), typeof(AbpNotificationsTemplatingModule), + typeof(AbpNotificationsCalendarModule), typeof(AbpWeChatWorkHandlersModule), typeof(AbpWeChatOfficialHandlersModule), typeof(AbpIdentityNotificationsModule), diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs index e63ff3150..56f796efc 100644 --- a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs @@ -87,7 +87,7 @@ public class WorkdayCalendarService : IWorkdayCalendarService, ITransientDepende return false; } if (_options.EnableWorkTimeRestriction && - !_options.DefaultWorkTimes.Any(timeRange => timeRange.StartTime >= time.TimeOfDay && timeRange.EndTime <= time.TimeOfDay)) + !_options.DefaultWorkTimes.Any(timeRange => time.TimeOfDay >= timeRange.StartTime && time.TimeOfDay <= timeRange.EndTime)) { return false; } @@ -109,7 +109,7 @@ public class WorkdayCalendarService : IWorkdayCalendarService, ITransientDepende if (calendar.EnableWorkTimeRestriction && calendar.WorkTimes != null) { - return calendar.WorkTimes.Any(x => x.StartTime >= time.TimeOfDay && x.EndTime <= time.TimeOfDay); + return calendar.WorkTimes.Any(timeRange => time.TimeOfDay >= timeRange.StartTime && time.TimeOfDay <= timeRange.EndTime); } return false; diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs index a24d997bd..f93beff5e 100644 --- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN/Abp/Notifications/Calendar/WorkdayCalendarPublishInterceptor.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System; using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.Timing; @@ -12,7 +11,7 @@ namespace LINGYUN.Abp.Notifications.Calendar; /// /// 工作日通知发布拦截器 /// -public class WorkdayCalendarPublishInterceptor : INotificationPublishInterceptor, ITransientDependency +public class WorkdayCalendarPublishInterceptor : INotificationPublishInterceptor { private readonly IClock _clock; private readonly ICurrentTenant _currentTenant; diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index c2023f0f5..5537e2c55 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -211,6 +211,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index e8693c8c6..287123617 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Exporter.MiniSoftware; +using LINGYUN.Abp.Notifications.Calendar; namespace LY.MicroService.Applications.Single; @@ -316,6 +317,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpNotificationsWeChatMiniProgramModule), // 通知模块 企业微信 typeof(AbpNotificationsWeChatWorkModule), + // 通知模块 工作日检查拦截器 + typeof(AbpNotificationsCalendarModule), // 多租户模块 版本 typeof(AbpMultiTenancyEditionsModule), diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj index 0660c8477..f947c5d5a 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj @@ -74,6 +74,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs index ca465dfb5..e98996175 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs @@ -23,6 +23,7 @@ using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.MessageService; using LINGYUN.Abp.MessageService.EntityFrameworkCore; using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.Notifications.Calendar; using LINGYUN.Abp.Notifications.Common; using LINGYUN.Abp.Notifications.Emailing; using LINGYUN.Abp.Notifications.EntityFrameworkCore; @@ -107,6 +108,7 @@ namespace LY.MicroService.RealtimeMessage; typeof(AbpNotificationsWeChatWorkModule), typeof(AbpNotificationsExceptionHandlingModule), typeof(AbpNotificationsTemplatingModule), + typeof(AbpNotificationsCalendarModule), typeof(AbpWeChatWorkHandlersModule), typeof(AbpWeChatOfficialHandlersModule), typeof(AbpIdentityNotificationsModule), From 4791c1f107f02c9f77057aac03a2288c83b8b59a Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 18 May 2026 15:39:57 +0800 Subject: [PATCH 10/40] fix: Specify the assembly to which the migration script belongs --- ...NameDbMigratorEntityFrameworkCoreModule.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs index 4e45b22f5..031bf89bb 100644 --- a/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs +++ b/aspnet-core/templates/micro/content/migrations/PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore/ProjectNameDbMigratorEntityFrameworkCoreModule.cs @@ -60,15 +60,16 @@ public class ProjectNameDbMigratorEntityFrameworkCoreModule : AbpModule Configure(options => { #if MySQL - options.UseMySQL(mysql => + options.UseMySQL(builder => { // see: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1960 - mysql.UseParameterizedCollectionMode(ParameterTranslationMode.Constant); + builder.UseParameterizedCollectionMode(ParameterTranslationMode.Constant); }); - options.UseMySQL(mysql => + options.UseMySQL(builder => { // see: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1960 - mysql.UseParameterizedCollectionMode(ParameterTranslationMode.Constant); + builder.UseParameterizedCollectionMode(ParameterTranslationMode.Constant); + builder.MigrationsAssembly(GetType().Assembly); }); #elif SqlServer options.UseSqlServer(); @@ -76,16 +77,26 @@ public class ProjectNameDbMigratorEntityFrameworkCoreModule : AbpModule { // see https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-database-transact-sql-compatibility-level?view=sql-server-ver16 // builder.UseCompatibilityLevel(150); + builder.MigrationsAssembly(GetType().Assembly); }); #elif Sqlite options.UseSqlite(); - options.UseSqlite(); + options.UseSqlite(builder => + { + builder.MigrationsAssembly(GetType().Assembly); + }); #elif Oracle || OracleDevart options.UseOracle(); - options.UseOracle(); + options.UseOracle(builder => + { + builder.MigrationsAssembly(GetType().Assembly); + }); #elif PostgreSql options.UseNpgsql(); - options.UseNpgsql(); + options.UseNpgsql(builder => + { + builder.MigrationsAssembly(GetType().Assembly); + }); #endif }); } From 1d66151d92379c9f4d38a1bc0844eb26e9d9f1ab Mon Sep 17 00:00:00 2001 From: colin Date: Tue, 19 May 2026 08:08:31 +0800 Subject: [PATCH 11/40] feat(ai): Disable API Key Auditlog --- .../Dtos/WorkspaceDefinitionRecordCreateOrUpdateDto.cs | 2 ++ .../Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordCreateOrUpdateDto.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordCreateOrUpdateDto.cs index 361ac7d50..5c94c209e 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordCreateOrUpdateDto.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Workspaces/Dtos/WorkspaceDefinitionRecordCreateOrUpdateDto.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Volo.Abp.Auditing; using Volo.Abp.ObjectExtending; using Volo.Abp.Validation; @@ -20,6 +21,7 @@ public abstract class WorkspaceDefinitionRecordCreateOrUpdateDto : ExtensibleObj [DynamicStringLength(typeof(WorkspaceDefinitionRecordConsts), nameof(WorkspaceDefinitionRecordConsts.MaxDescriptionLength))] public string? Description { get; set; } + [DisableAuditing] [DynamicStringLength(typeof(WorkspaceDefinitionRecordConsts), nameof(WorkspaceDefinitionRecordConsts.MaxApiKeyLength))] public string? ApiKey { get; set; } diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs index 489adf94c..93ea50252 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs @@ -1,5 +1,6 @@ using System; using Volo.Abp; +using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain.Entities.Auditing; @@ -16,6 +17,7 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot public string? Description { get; set; } + [DisableAuditing] public string? ApiKey { get; private set; } public string? ApiBaseUrl { get; private set; } From 01d168d378b77f27167afd26d2e1e5f46434272d Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 21 May 2026 09:35:00 +0800 Subject: [PATCH 12/40] feat: Change the file name of the calendar module --- .../LINGYUN.Abp.Calendar/FodyWeavers.xsd | 30 +++++++++++++++++++ .../LINGYUN.Abp.Calendar.csproj | 4 +-- .../LINGYUN/Abp/Calendar/AbpCalendarModule.cs | 4 +++ .../FodyWeavers.xsd | 30 +++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xsd create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xsd diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xsd b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj index 489ab7fe2..896eeebb1 100644 --- a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj @@ -5,8 +5,8 @@ net8.0;net9.0;net10.0 - LINGYUN.Abp.WorkdayCalendar - LINGYUN.Abp.WorkdayCalendar + LINGYUN.Abp.Calendar + LINGYUN.Abp.Calendar false false false diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs index a52b9aadf..3705bf214 100644 --- a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs +++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs @@ -6,4 +6,8 @@ namespace LINGYUN.Abp.Calendar; [DependsOn(typeof(AbpTimingModule))] public class AbpCalendarModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(context.Configuration.GetSection("Calendar")); + } } diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xsd b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file From fef156fbee02f69e101aaa75bf99a9bff695ae4f Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 21 May 2026 10:15:22 +0800 Subject: [PATCH 13/40] feat: Add request body to the http tool --- .../LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs index f1c646086..df2c7a791 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AI.Tools.Http/LINGYUN/Abp/AI/Tools/Http/HttpAITool.cs @@ -8,6 +8,7 @@ using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using Volo.Abp.Http.Client.Authentication; +using Volo.Abp.Json; using Volo.Abp.MultiTenancy; using Volo.Abp.Timing; using Volo.Abp.Tracing; @@ -22,7 +23,9 @@ public class HttpAITool Context = context; } - public async virtual Task InvokeAsync(IDictionary? paramters = null) + public async virtual Task InvokeAsync( + IDictionary? paramters = null, + object? body = null) { // Abp远程服务适配 //var remoteService = Context.ToolDefinition.GetRemoteServiceOrNull(); @@ -90,6 +93,12 @@ public class HttpAITool Context.ToolDefinition.GetHttpMethod(), requestUri); + if (body != null) + { + var jsonSerializer = Context.ServiceProvider.GetRequiredService(); + httpRequestMessage.Content = new StringContent(jsonSerializer.Serialize(body)); + } + var headers = Context.ToolDefinition.GetHttpHeaders(); foreach (var header in headers) { @@ -148,6 +157,7 @@ public class HttpAITool //X-Requested-With requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest"); + requestMessage.Headers.Add("X-Requested-From", "abp-ai-httptool"); //Timezone var currentTimezoneProvider = Context.ServiceProvider.GetRequiredService(); From 5550ce36f7ef8ffd7d362d46a1952a659aa87455 Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 21 May 2026 18:27:45 +0800 Subject: [PATCH 14/40] feat: Enhance blob management module - Add the interface for generating download links - Alibaba Cloud Object Storage adds configuration for the expiration time of pre-signed links - Tencent Cloud Object Storage adds configuration for the expiration time of pre-signed links - Add generation of download url feature - Add the setting item for the expiration time of the generated download url - Add the interface for parsing file ContentType - Integrate the MimeCheck module to parse the Content-Type of the file --- .../LINGYUN.MicroService.SingleProject.slnx | 2 + .../TencentBlobProviderConfiguration.cs | 10 +++ .../TencentBlobProviderConfigurationNames.cs | 4 + .../Tencent/TencentCloudBlobProvider.cs | 2 +- .../LINGYUN.Abp.BlobStoring.Aliyun.csproj | 3 +- .../Aliyun/AbpBlobStoringAliyunModule.cs | 5 ++ .../BlobStoring/Aliyun/AliyunBlobProvider.cs | 12 ++- .../Aliyun/AliyunBlobProviderConfiguration.cs | 10 +++ .../AliyunBlobProviderConfigurationNames.cs | 4 + ...lientFactoryServiceCollectionExtensions.cs | 18 ++++ .../Aliyun/AliyunBlobProvider.cs | 58 +++++++++++-- .../Dtos/BlobDownloadByKeyInput.cs | 12 +++ .../Abp/BlobManagement/IBlobAppService.cs | 4 + ...bManagementPermissionDefinitionProvider.cs | 2 + .../BlobManagementPermissionNames.cs | 2 + .../Abp/BlobManagement/BlobAppService.cs | 16 ---- .../Abp/BlobManagement/BlobAppServiceBase.cs | 52 ++++++++--- .../BlobWithoutContainerAppService.cs | 18 ---- .../Integration/BlobIntegrationService.cs | 13 +-- .../BlobManagement/PublicBlobAppService.cs | 14 +-- ...BlobManagementContentTypeResolveOptions.cs | 15 ++++ .../BlobContentTypeResolveContext.cs | 33 +++++++ ...BlobManagementFeatureDefinitionProvider.cs | 7 +- .../Features/BlobManagementFeatureNames.cs | 4 + .../IBlobContentTypeResolveContributor.cs | 10 +++ .../Localization/Resources/en.json | 5 ++ .../Localization/Resources/zh-Hans.json | 5 ++ ...BlobManagementSettingDefinitionProvider.cs | 11 +++ .../Settings/BlobManagementSettingNames.cs | 7 +- .../BlobManagement/BlobContentTypeResolver.cs | 71 +++++++++++++++ .../BlobDownloadKeyCacheItem.cs | 24 +++++ .../LINGYUN/Abp/BlobManagement/BlobManager.cs | 87 ++++++++++++++++++- .../IBlobContentTypeResolver.cs | 9 ++ .../Abp/BlobManagement/IBlobProvider.cs | 10 ++- .../FileSystem/FileSystemBlobProvider.cs | 13 ++- .../AbpBlobManagementHttpApiModule.cs | 14 +++ .../Abp/BlobManagement/BlobController.cs | 14 +++ ...ensionBlobContentTypeResolveContributor.cs | 24 +++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++++ ...INGYUN.Abp.BlobManagement.MimeCheck.csproj | 25 ++++++ .../AbpBlobManagementMimeCheckModule.cs | 15 ++++ ...eCheckBlobContentTypeResolveContributor.cs | 33 +++++++ .../BlobManagement/Minio/MinioBlobProvider.cs | 57 ++++++++---- .../BlobManagementSettingAppService.cs | 5 ++ .../Tencent/TencentBlobProvider.cs | 49 ++++++++--- ...LY.MicroService.Applications.Single.csproj | 1 + .../MicroServiceApplicationsSingleModule.cs | 3 + 48 files changed, 737 insertions(+), 108 deletions(-) create mode 100644 aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/Microsoft/Extensions/DependencyInjection/AliyunHttpClientFactoryServiceCollectionExtensions.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/AbpBlobManagementContentTypeResolveOptions.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobContentTypeResolveContext.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolveContributor.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobContentTypeResolver.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolver.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/FileExtensionBlobContentTypeResolveContributor.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xml create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xsd create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN.Abp.BlobManagement.MimeCheck.csproj create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/AbpBlobManagementMimeCheckModule.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/MimeCheckBlobContentTypeResolveContributor.cs diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.slnx b/aspnet-core/LINGYUN.MicroService.SingleProject.slnx index 7f687aba2..5e401511a 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.slnx +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.slnx @@ -11,6 +11,7 @@ + @@ -211,6 +212,7 @@ + diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfiguration.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfiguration.cs index 5ebd4b5ba..3e6e85705 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfiguration.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfiguration.cs @@ -53,6 +53,16 @@ public class TencentBlobProviderConfiguration } } + /// + /// Default value: 600. + /// + public int PresignedGetExpirySeconds { + get => _containerConfiguration.GetConfigurationOrDefault(TencentBlobProviderConfigurationNames.PresignedGetExpirySeconds, _defaultExpirySeconds); + set => _containerConfiguration.SetConfiguration(TencentBlobProviderConfigurationNames.PresignedGetExpirySeconds, value); + } + + private int _defaultExpirySeconds = 600; + private readonly BlobContainerConfiguration _containerConfiguration; public TencentBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfigurationNames.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfigurationNames.cs index 50b15be12..804c5813e 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfigurationNames.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentBlobProviderConfigurationNames.cs @@ -22,4 +22,8 @@ public static class TencentBlobProviderConfigurationNames /// 创建命名空间时防盗链列表 /// public const string CreateBucketReferer = "Tencent:OSS:CreateBucketReferer"; + /// + /// 生成预签名Uri的过期时间(s) + /// + public const string PresignedGetExpirySeconds = "Tencent:OSS:PresignedGetExpirySeconds"; } diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentCloudBlobProvider.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentCloudBlobProvider.cs index 65429bdfa..11b6e09fc 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentCloudBlobProvider.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.BlobStoring.Tencent/LINGYUN/Abp/BlobStoring/Tencent/TencentCloudBlobProvider.cs @@ -78,7 +78,7 @@ public class TencentCloudBlobProvider : BlobProviderBase, ITransientDependency key = blobName, //对象键 httpMethod = "GET", //HTTP 请求方法 isHttps = true, //生成 HTTPS 请求 URL - signDurationSecond = 600, //请求签名时间为600s + signDurationSecond = configuration.PresignedGetExpirySeconds, //请求签名时间为600s headers = null, //签名中需要校验的 header queryParameters = null //签名中需要校验的 URL 中请求参数 }; diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj index faad574d2..59822d893 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj @@ -4,7 +4,7 @@ - netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0 + net8.0;net9.0;net10.0 LINGYUN.Abp.BlobStoring.Aliyun LINGYUN.Abp.BlobStoring.Aliyun false @@ -16,6 +16,7 @@ + diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs index 5a52f79a1..cb88a938c 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Aliyun; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.BlobStoring; using Volo.Abp.Modularity; @@ -9,6 +10,10 @@ namespace LINGYUN.Abp.BlobStoring.Aliyun; typeof(AbpAliyunModule))] public class AbpBlobStoringAliyunModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAliyunHttpClient(); + } // 需要时引用配置 //public override void ConfigureServices(ServiceConfigurationContext context) //{ diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs index 63c09c373..0064ce2cc 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs @@ -1,8 +1,10 @@ using Aliyun.OSS; using LINGYUN.Abp.Aliyun.Features; +using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.IO; +using System.Net.Http; using System.Threading.Tasks; using Volo.Abp.BlobStoring; using Volo.Abp.DependencyInjection; @@ -14,13 +16,16 @@ namespace LINGYUN.Abp.BlobStoring.Aliyun; public class AliyunBlobProvider : BlobProviderBase, ITransientDependency { protected IOssClientFactory OssClientFactory { get; } + protected IHttpClientFactory HttpClientFactory { get; } protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; } public AliyunBlobProvider( IOssClientFactory ossClientFactory, + IHttpClientFactory httpClientFactory, IAliyunBlobNameCalculator aliyunBlobNameCalculator) { OssClientFactory = ossClientFactory; + HttpClientFactory = httpClientFactory; AliyunBlobNameCalculator = aliyunBlobNameCalculator; } @@ -55,8 +60,11 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency return null; } - var ossObject = ossClient.GetObject(GetBucketName(args), blobName); - return ossObject.Content; + var downloadUri = ossClient.GeneratePresignedUri(GetBucketName(args), blobName); + + var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + + return await httpClient.GetStreamAsync(downloadUri, args.CancellationToken); } public override async Task SaveAsync(BlobProviderSaveArgs args) diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs index 901053d0c..d7efa95a4 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs @@ -40,6 +40,16 @@ public class AliyunBlobProviderConfiguration } } + /// + /// Default value: 7 * 24 * 3600. + /// + public int PresignedGetExpirySeconds { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.PresignedGetExpirySeconds, _defaultExpirySeconds); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.PresignedGetExpirySeconds, value); + } + + private int _defaultExpirySeconds = 7 * 24 * 3600; + private readonly BlobContainerConfiguration _containerConfiguration; public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs index 13e0c3c9c..e3e0c9221 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs @@ -18,4 +18,8 @@ public static class AliyunBlobProviderConfigurationNames /// 创建命名空间时防盗链列表 /// public const string CreateBucketReferer = "Aliyun:OSS:CreateBucketReferer"; + /// + /// 生成预签名Uri的过期时间(s) + /// + public const string PresignedGetExpirySeconds = "Aliyun:OSS:PresignedGetExpirySeconds"; } diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/Microsoft/Extensions/DependencyInjection/AliyunHttpClientFactoryServiceCollectionExtensions.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/Microsoft/Extensions/DependencyInjection/AliyunHttpClientFactoryServiceCollectionExtensions.cs new file mode 100644 index 000000000..b28410930 --- /dev/null +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/Microsoft/Extensions/DependencyInjection/AliyunHttpClientFactoryServiceCollectionExtensions.cs @@ -0,0 +1,18 @@ +using System.Net.Http; + +namespace Microsoft.Extensions.DependencyInjection; +internal static class AliyunHttpClientFactoryServiceCollectionExtensions +{ + private const string HttpClientName = "__AliyunBlobStoringApiClient"; + public static IServiceCollection AddAliyunHttpClient(this IServiceCollection services) + { + services.AddHttpClient(HttpClientName); + + return services; + } + + public static HttpClient CreateAliyunHttpClient(this IHttpClientFactory httpClientFactory) + { + return httpClientFactory.CreateClient(HttpClientName); + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs index 50157e116..912320b7a 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs @@ -7,8 +7,9 @@ using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Volo.Abp; +using Volo.Abp.BlobStoring; using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; namespace LINGYUN.Abp.BlobManagement.Aliyun; @@ -17,24 +18,30 @@ public class AliyunBlobProvider : IBlobProvider public const string ProviderName = "Aliyun"; public string Name => ProviderName; + protected IClock Clock { get; } protected IConfiguration Configuration { get; } protected ICurrentTenant CurrentTenant { get; } protected IOssClientFactory OssClientFactory { get; } protected IHttpClientFactory HttpClientFactory { get; } protected AliyunBlobNamingNormalizer BlobNamingNormalizer { get; } + protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } public AliyunBlobProvider( + IClock clock, IConfiguration configuration, ICurrentTenant currentTenant, IOssClientFactory ossClientFactory, IHttpClientFactory httpClientFactory, - AliyunBlobNamingNormalizer blobNamingNormalizer) + AliyunBlobNamingNormalizer blobNamingNormalizer, + IBlobContainerConfigurationProvider configurationProvider) { + Clock = clock; Configuration = configuration; CurrentTenant = currentTenant; OssClientFactory = ossClientFactory; HttpClientFactory = httpClientFactory; BlobNamingNormalizer = blobNamingNormalizer; + ConfigurationProvider = configurationProvider; } public async virtual Task CreateContainerAsync( @@ -90,6 +97,29 @@ public class AliyunBlobProvider : IBlobProvider string containerName, string blobName, CancellationToken cancellationToken = default) + { + var configuration = GetBlobConfiguration(); + + var downloadUrl = await GenerateDownloadUrlAsync( + containerName, + blobName, + TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), + cancellationToken); + if (downloadUrl.IsNullOrWhiteSpace()) + { + return null; + } + + var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + + return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + } + + public async virtual Task GenerateDownloadUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + CancellationToken cancellationToken = default) { var client = await CreateClientAsync(); var bucket = NormalizeContainerName(containerName); @@ -100,11 +130,7 @@ public class AliyunBlobProvider : IBlobProvider return null; } - var downloadUrl = client.GeneratePresignedUri(bucket, objectName); - - var httpClient = HttpClientFactory.CreateAliyunHttpClient(); - - return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + return client.GeneratePresignedUri(bucket, objectName, Clock.Now.Add(expiration)).ToString(); } public virtual Task CreateFolderAsync( @@ -120,7 +146,8 @@ public class AliyunBlobProvider : IBlobProvider public async virtual Task UploadBlobAsync( string containerName, string blobName, - Stream content, + Stream content, + string? contentType = null, CancellationToken cancellationToken = default) { var client = await CreateClientAsync(); @@ -129,7 +156,20 @@ public class AliyunBlobProvider : IBlobProvider CreateBucketIfNotExists(client, bucket); - client.PutObject(bucket, objectName, content); + var objectMetadata = new ObjectMetadata(); + if (!contentType.IsNullOrWhiteSpace()) + { + objectMetadata.ContentType = contentType; + } + + client.PutObject(bucket, objectName, content, objectMetadata); + } + + protected virtual AliyunBlobProviderConfiguration GetBlobConfiguration() + { + var configuration = ConfigurationProvider.Get(); + var blobConfiguration = configuration.GetAliyunConfiguration(); + return blobConfiguration; } protected async virtual Task CreateClientAsync() diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs new file mode 100644 index 000000000..fb5da0020 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs @@ -0,0 +1,12 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.BlobManagement.Dtos; + +public class BlobDownloadByKeyInput +{ + public Guid? TenantId { get; set; } + + [Required] + public string Key { get; set; } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs index 3ea16c27a..2d4679569 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs @@ -17,6 +17,10 @@ public interface IBlobAppService : IApplicationService Task DeleteAsync(Guid id); + Task GenerateDownloadUrlAsync(Guid id); + + Task DownloadAsync(BlobDownloadByKeyInput input); + Task GetContentAsync(Guid id); Task GetContentByNameAsync(BlobDownloadByNameInput input); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionDefinitionProvider.cs index afacc3089..91bbbc778 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionDefinitionProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionDefinitionProvider.cs @@ -27,6 +27,8 @@ public class BlobManagementPermissionDefinitionProvider : PermissionDefinitionPr blob.AddChild(BlobManagementPermissionNames.Blob.Delete, L("Permission:Delete")); blob.AddChild(BlobManagementPermissionNames.Blob.Download, L("Permission:Download")) .RequireFeatures(BlobManagementFeatureNames.Blob.DownloadFile); + blob.AddChild(BlobManagementPermissionNames.Blob.GenerateDownloadUrl, L("Permission:GenerateDownloadUrl")) + .RequireFeatures(BlobManagementFeatureNames.Blob.GenerateDownloadUrl); context.AddResourcePermission( name: BlobManagementPermissionNames.Blob.Resources.Delete, diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionNames.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionNames.cs index 56bca0d0e..c062e8bda 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionNames.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Permissions/BlobManagementPermissionNames.cs @@ -23,6 +23,8 @@ public static class BlobManagementPermissionNames public const string Download = Default + ".Download"; + public const string GenerateDownloadUrl = Default + ".GenerateDownloadUrl"; + public const string ManagePermissions = Default + ".ManagePermissions"; public static class Resources diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs index 8dab178a9..689395ef4 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs @@ -1,7 +1,6 @@ using LINGYUN.Abp.BlobManagement.Dtos; using LINGYUN.Abp.BlobManagement.Features; using LINGYUN.Abp.BlobManagement.Permissions; -using LINGYUN.Abp.Features.LimitValidation; using System.Threading.Tasks; using Volo.Abp.Content; using Volo.Abp.Features; @@ -23,11 +22,6 @@ public class BlobAppService : BlobAppServiceBase, IBlobAppService GetListPolicyName = BlobManagementPermissionNames.Blob.Default; } - [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.UploadLimit, - BlobManagementFeatureNames.Blob.UploadInterval, - LimitPolicy.Month)] public async virtual Task CreateChunkFileAsync(BlobFileChunkCreateDto input) { await CheckCreatePolicyAsync(); @@ -35,11 +29,6 @@ public class BlobAppService : BlobAppServiceBase, IBlobAppService await base.CreateChunkFileAsync(input.ContainerId.ToString(), input); } - [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.UploadLimit, - BlobManagementFeatureNames.Blob.UploadInterval, - LimitPolicy.Month)] public async virtual Task CreateFileAsync(BlobFileCreateDto input) { await CheckCreatePolicyAsync(); @@ -58,11 +47,6 @@ public class BlobAppService : BlobAppServiceBase, IBlobAppService return await base.CreateFolderAsync(blobContainer, input); } - [RequiresFeature(BlobManagementFeatureNames.Blob.DownloadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.DownloadLimit, - BlobManagementFeatureNames.Blob.DownloadInterval, - LimitPolicy.Month)] public async virtual Task GetContentByNameAsync(BlobDownloadByNameInput input) { var blobContainer = await BlobContainerRepository.GetByNameAsync(input.ContainerName); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs index 35d461b7f..683e6b1ce 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs @@ -1,7 +1,5 @@ using LINGYUN.Abp.BlobManagement.Dtos; -using LINGYUN.Abp.BlobManagement.Features; using LINGYUN.Abp.BlobManagement.Permissions; -using LINGYUN.Abp.Features.LimitValidation; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; @@ -13,7 +11,6 @@ using System.Web; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Content; -using Volo.Abp.Features; using Volo.Abp.Specifications; namespace LINGYUN.Abp.BlobManagement; @@ -49,11 +46,44 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService await DeleteBlobAsync(blob); } - [RequiresFeature(BlobManagementFeatureNames.Blob.DownloadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.DownloadLimit, - BlobManagementFeatureNames.Blob.DownloadInterval, - LimitPolicy.Month)] + public async virtual Task GenerateDownloadUrlAsync(Guid id) + { + var blob = await BlobRepository.GetAsync(id); + var blobContainer = await BlobContainerRepository.GetAsync(blob.ContainerId); + + await CheckGetPolicyAsync(blob); + + var fallbackUrlPrefix = blob.TenantId.HasValue + ? $"/api/{BlobManagementRemoteServiceConsts.ModuleName}/blobs/download/t/{blob.TenantId:N}" + : $"/api/{BlobManagementRemoteServiceConsts.ModuleName}/blobs/download"; + + var downloadUrl = await BlobManager.GenerateDownloadUrlAsync( + blobContainer, + blob, + fallbackUrlPrefix); + + return downloadUrl; + } + + public async virtual Task DownloadAsync(BlobDownloadByKeyInput input) + { + using (CurrentTenant.Change(input.TenantId)) + { + var blob = await BlobManager.FindBlobByDownloadKeyAsync(input.Key); + if (blob == null) + { + return new RemoteStreamContent(Stream.Null, input.Key); + } + + // 临时下载链接一般用于临时预览与下载, 过期时间短, 不校验权限 + // await CheckGetPolicyAsync(blob); + + var stream = await BlobManager.DownloadBlobsync(blob); + + return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); + } + } + public async virtual Task GetContentAsync(Guid id) { var blob = await BlobRepository.GetAsync(id); @@ -62,7 +92,7 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService var stream = await BlobManager.DownloadBlobsync(blob); - return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, blob.Size); + return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); } public async virtual Task GetAsync(Guid id) @@ -120,7 +150,7 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService blobStream.Length, parentBlob); - blob = await BlobManager.UploadBlobAsync(blobContainer, blob, blobStream, input.File.ContentType, input.CompareMd5); + blob = await BlobManager.UploadBlobAsync(blobContainer, blob, blobStream, input.CompareMd5); return ObjectMapper.Map(blob); } @@ -167,7 +197,7 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService var stream = await BlobManager.DownloadBlobsync(blob); - return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, blob.Size); + return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); } protected async virtual Task FindBlobByNameAsync(BlobContainer blobContainer, string name) diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs index 2b0d608ba..66ed740d8 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs @@ -1,10 +1,7 @@ using LINGYUN.Abp.BlobManagement.Dtos; -using LINGYUN.Abp.BlobManagement.Features; -using LINGYUN.Abp.Features.LimitValidation; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Content; -using Volo.Abp.Features; namespace LINGYUN.Abp.BlobManagement; @@ -20,11 +17,6 @@ public abstract class BlobWithoutContainerAppService : BlobAppServiceBase { } - [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.UploadLimit, - BlobManagementFeatureNames.Blob.UploadInterval, - LimitPolicy.Month)] public async virtual Task CreateChunkFileAsync(BlobFileChunkCreateWithoutContainerDto input) { await CheckCreatePolicyAsync(); @@ -32,11 +24,6 @@ public abstract class BlobWithoutContainerAppService : BlobAppServiceBase await base.CreateChunkFileAsync(ContainerName, input); } - [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.UploadLimit, - BlobManagementFeatureNames.Blob.UploadInterval, - LimitPolicy.Month)] public async virtual Task CreateFileAsync(BlobFileCreateWithoutContainerDto input) { await CheckCreatePolicyAsync(); @@ -55,11 +42,6 @@ public abstract class BlobWithoutContainerAppService : BlobAppServiceBase return await base.CreateFolderAsync(blobContainer, input); } - [RequiresFeature(BlobManagementFeatureNames.Blob.DownloadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.DownloadLimit, - BlobManagementFeatureNames.Blob.DownloadInterval, - LimitPolicy.Month)] public async virtual Task GetContentByNameAsync(string name) { var blobContainer = await BlobContainerRepository.GetByNameAsync(ContainerName); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs index 9bfa786c4..367da5ba9 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs @@ -1,7 +1,6 @@ using LINGYUN.Abp.BlobManagement.Dtos; using LINGYUN.Abp.BlobManagement.Features; using LINGYUN.Abp.BlobManagement.Integration.Dtos; -using LINGYUN.Abp.Features.LimitValidation; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -27,11 +26,6 @@ public class BlobIntegrationService : BlobAppServiceBase, IBlobIntegrationServic { } - [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.UploadLimit, - BlobManagementFeatureNames.Blob.UploadInterval, - LimitPolicy.Month)] public async virtual Task CreateAsync(BlobFileCreateIntegrationDto input) { var blobContainer = await BlobContainerRepository.GetByNameAsync(input.ContainerName); @@ -62,7 +56,7 @@ public class BlobIntegrationService : BlobAppServiceBase, IBlobIntegrationServic parentBlob, input.Overwrite == true); - await BlobManager.UploadBlobAsync(blobContainer, blob, blobStream, input.File.ContentType); + await BlobManager.UploadBlobAsync(blobContainer, blob, blobStream); return ObjectMapper.Map(blob); } @@ -96,11 +90,6 @@ public class BlobIntegrationService : BlobAppServiceBase, IBlobIntegrationServic } } - [RequiresFeature(BlobManagementFeatureNames.Blob.DownloadFile)] - [RequiresLimitFeature( - BlobManagementFeatureNames.Blob.DownloadLimit, - BlobManagementFeatureNames.Blob.DownloadInterval, - LimitPolicy.Month)] public async virtual Task GetContentAsync(BlobFileGetByNameIntegrationDto input) { try diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/PublicBlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/PublicBlobAppService.cs index ca63fd966..b30a3de6e 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/PublicBlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/PublicBlobAppService.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.BlobManagement.Features; +using LINGYUN.Abp.BlobManagement.Permissions; using System.Threading.Tasks; using Volo.Abp.Features; @@ -15,16 +16,19 @@ public class PublicBlobAppService : BlobWithoutContainerAppService, IPublicBlobA BlobManager blobManager) : base(blobContainerRepository, blobRepository, blobManager) { + DeletePolicyName = BlobManagementPermissionNames.Blob.Delete; } - protected override Task CheckGetPolicyAsync(string containerName, Blob blob) + protected async override Task CheckGetPolicyAsync(string containerName, Blob blob) { - // 公共文件访问不校验权限 - return Task.CompletedTask; + if (!CurrentUser.IsAuthenticated) + { + await FeatureChecker.CheckEnabledAsync(BlobManagementFeatureNames.PublicAccess); + } } - protected override Task CheckDeletePolicyAsync(string containerName, Blob blob) + protected async override Task CheckDeletePolicyAsync(string containerName, Blob blob) { - return base.CheckDeletePolicyAsync(blob); + await CheckPolicyAsync(DeletePolicyName); } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/AbpBlobManagementContentTypeResolveOptions.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/AbpBlobManagementContentTypeResolveOptions.cs new file mode 100644 index 000000000..43d9ec924 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/AbpBlobManagementContentTypeResolveOptions.cs @@ -0,0 +1,15 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace LINGYUN.Abp.BlobManagement; + +public class AbpBlobManagementContentTypeResolveOptions +{ + [NotNull] + public List BlobContentTypeResolvers { get; } + + public AbpBlobManagementContentTypeResolveOptions() + { + BlobContentTypeResolvers = new List(); + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobContentTypeResolveContext.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobContentTypeResolveContext.cs new file mode 100644 index 000000000..66c61164c --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobContentTypeResolveContext.cs @@ -0,0 +1,33 @@ +using System; +using System.IO; + +namespace LINGYUN.Abp.BlobManagement; + +public class BlobContentTypeResolveContext +{ + public IServiceProvider ServiceProvider { get; } + public string BlobName { get; } + public Stream Stream { get; } + public bool Handled { get; private set; } + public string? ContentType { get; private set; } + public BlobContentTypeResolveContext( + IServiceProvider serviceProvider, + string blobName, + Stream stream) + { + ServiceProvider = serviceProvider; + BlobName = blobName; + Stream = stream; + } + + public void Success(string contentType) + { + ContentType = contentType; + Handled = true; + } + + public bool HasResolvedContentType() + { + return Handled && !ContentType.IsNullOrWhiteSpace(); + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureDefinitionProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureDefinitionProvider.cs index 7109dc899..f3af7b7f2 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureDefinitionProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureDefinitionProvider.cs @@ -32,7 +32,12 @@ public class BlobManagementFeatureDefinitionProvider : FeatureDefinitionProvider displayName: L("Features:DisplayName:EnableBlob"), description: L("Features:Description:EnableBlob"), valueType: new ToggleStringValueType(new BooleanValueValidator())); - + blobDefaultFeature.CreateChild( + name: BlobManagementFeatureNames.Blob.GenerateDownloadUrl, + defaultValue: true.ToString(), + displayName: L("Features:DisplayName:GenerateDownloadUrl"), + description: L("Features:Description:GenerateDownloadUrl"), + valueType: new ToggleStringValueType(new BooleanValueValidator())); blobDefaultFeature.CreateChild( name: BlobManagementFeatureNames.Blob.DownloadFile, defaultValue: true.ToString(), diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureNames.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureNames.cs index adfd8d833..67bee1eb4 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureNames.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Features/BlobManagementFeatureNames.cs @@ -20,6 +20,10 @@ public static class BlobManagementFeatureNames /// public const string Enable = Default + ".Enable"; /// + /// 生成临时文件下载链接 + /// + public const string GenerateDownloadUrl = Default + ".GenerateDownloadUrl"; + /// /// 下载文件功能 /// public const string DownloadFile = Default + ".DownloadFile"; diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolveContributor.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolveContributor.cs new file mode 100644 index 000000000..a86d8b386 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolveContributor.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.BlobManagement; + +public interface IBlobContentTypeResolveContributor +{ + string Name { get; } + int Priority { get; } + Task ResolveAsync(BlobContentTypeResolveContext context); +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json index cd79e95ae..7babc31ef 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json @@ -10,6 +10,7 @@ "Permission:Download": "Download", "Permission:Blob:Delete": "Delete Blob", "Permission:Blob:View": "View Blob", + "Permission:GenerateDownloadUrl": "Generate Download Url", "Features:BlobManagement": "Blob Management", "Features:DisplayName:EnableBlobManagement": "Enable Blob Management", "Features:Description:EnableBlobManagement": "Enable to give the application the ability to have an blob storage module.", @@ -29,6 +30,8 @@ "Features:Description:UploadLimit": "Limits the total number of file uploads within a specified period", "Features:DisplayName:UploadInterval": "Limit Uploads Interval", "Features:Description:UploadInterval": "The update period that limits the number of files uploaded. The time scale is: month. Default: 1", + "Features:DisplayName:GenerateDownloadUrl": "Generate Download Url", + "Features:Description:GenerateDownloadUrl": "Whether to allow users to generate download links for temporary files", "BlobManagement:001001": "A blob container named {Name} already exists!", "BlobManagement:001002": "The blob container is not empty and cannot be deleted!", "BlobManagement:001003": "The blob container is the system container and cannot be deleted!", @@ -55,6 +58,8 @@ "Description:FileLimitLength": "Limit size of uploaded file in MB", "DisplayName:AllowFileExtensions": "File extension", "Description:AllowFileExtensions": "List of allowed extensions to upload files, with multiple extensions separated by, don't need a notation", + "DisplayName:GenerateDownloadUrlExpirySeconds": "Download Url Expiry Seconds", + "Description:GenerateDownloadUrlExpirySeconds": "Set the validity period for the temporary download link (in seconds). If not set or left blank, it defaults to 600 seconds.", "DisplayName:BlobManagement": "Blob Management", "DisplayName:Blobs": "Blobs", "DisplayName:CreationTime": "Creation Time", diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json index 4d1bf8b24..59f356251 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json @@ -10,6 +10,7 @@ "Permission:Download": "下载", "Permission:Blob:Delete": "删除存储对象", "Permission:Blob:View": "查看存储对象", + "Permission:GenerateDownloadUrl": "生成下载链接", "Features:BlobManagement": "对象存储", "Features:DisplayName:EnableBlobManagement": "启用对象存储", "Features:Description:EnableBlobManagement": "启用以使应用程序拥有对象存储模块的能力.", @@ -29,6 +30,8 @@ "Features:Description:UploadLimit": "在指定的周期内限制上传文件的总次数", "Features:DisplayName:UploadInterval": "限制上传文件周期", "Features:Description:UploadInterval": "限制上传文件次数的更新周期,时间刻度为:月,默认:1", + "Features:DisplayName:GenerateDownloadUrl": "生成文件下载链接", + "Features:Description:GenerateDownloadUrl": "是否允许用户生成临时文件下载链接", "BlobManagement:001001": "已经存在名为 {Name} 的存储容器!", "BlobManagement:001002": "存储容器非空,不可删除!", "BlobManagement:001003": "存储容器为系统容器,不可删除!", @@ -55,6 +58,8 @@ "Description:FileLimitLength": "上传文件的限制大小,单位(MB)", "DisplayName:AllowFileExtensions": "文件扩展名", "Description:AllowFileExtensions": "允许的上传文件扩展名列表,多个扩展名以,分隔,无需输入.符号", + "DisplayName:GenerateDownloadUrlExpirySeconds": "生成临时下载链接有效期", + "Description:GenerateDownloadUrlExpirySeconds": "生成临时下载链接有效时间, 单位(s), 未设置或为空时默认600s.", "DisplayName:BlobManagement": "对象存储", "DisplayName:Blobs": "存储管理", "DisplayName:CreationTime": "创建时间", diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs index 9160143dd..e8d1f886f 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs @@ -37,6 +37,17 @@ public class BlobManagementSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName), + new SettingDefinition( + name: BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds, + defaultValue: BlobManagementSettingNames.DefaultGenerateDownloadUrlExpirySeconds.ToString(), + displayName: L("DisplayName:GenerateDownloadUrlExpirySeconds"), + description: L("Description:GenerateDownloadUrlExpirySeconds"), + isVisibleToClients: true) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), }; } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingNames.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingNames.cs index cbd6a3fb1..853153820 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingNames.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingNames.cs @@ -11,7 +11,12 @@ public static class BlobManagementSettingNames /// 允许的文件扩展名类型 /// public const string AllowFileExtensions = GroupName + ".AllowFileExtensions"; + /// + /// 生成临时下载链接有效期(s) + /// + public const string GenerateDownloadUrlExpirySeconds = GroupName + ".GenerateDownloadUrlExpirySeconds"; public const long DefaultFileLimitLength = 5L; - public const string DefaultAllowFileExtensions = "dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pptx,potx,ppt,pot,chm"; + public const double DefaultGenerateDownloadUrlExpirySeconds = 600d; + public const string DefaultAllowFileExtensions = "dll,zip,rar,txt,log,xml,config,json,jpeg,jpg,png,bmp,ico,xlsx,xltx,xls,xlt,docs,dots,doc,dot,pdf,pptx,potx,ppt,pot,chm"; } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobContentTypeResolver.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobContentTypeResolver.cs new file mode 100644 index 000000000..0ef93ff89 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobContentTypeResolver.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.BlobManagement; + +public class BlobContentTypeResolver : IBlobContentTypeResolver, ITransientDependency +{ + public ILogger Logger { get; set; } + + protected IServiceScopeFactory ServiceScopeFactory { get; } + protected AbpBlobManagementContentTypeResolveOptions Options { get; } + + public BlobContentTypeResolver( + IOptions options, + IServiceScopeFactory serviceScopeFactory) + { + ServiceScopeFactory = serviceScopeFactory; + Options = options.Value; + + Logger = NullLogger.Instance; + } + + public async virtual Task ResolveContentTypeAsync(string blobName, Stream blobStream) + { + string? result = null; + + Logger.LogDebug("Starting resolving content type..."); + using (var serviceScope = ServiceScopeFactory.CreateScope()) + { + var context = new BlobContentTypeResolveContext(serviceScope.ServiceProvider, blobName, blobStream); + + foreach (var blobContentTypeResolver in Options.BlobContentTypeResolvers.OrderByDescending(x => x.Priority)) + { + var originalPosition = context.Stream.CanSeek ? context.Stream.Position : -1; + + Logger.LogDebug("Trying to resolve content type '{Name}'...", blobContentTypeResolver.Name); + + await blobContentTypeResolver.ResolveAsync(context); + + if (originalPosition >= 0 && context.Stream.CanSeek) + { + context.Stream.Position = originalPosition; + } + + if (context.HasResolvedContentType()) + { + result = context.ContentType; + + Logger.LogDebug("Content type resolved by '{Name}' as '{ContentType}'.", blobContentTypeResolver.Name, result); + break; + } + } + } + + if (result.IsNullOrWhiteSpace()) + { + Logger.LogWarning("No provider can resolve content type. Using the default \"application/octet-stream\"."); + + return "application/octet-stream"; + } + + return result; + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs new file mode 100644 index 000000000..7c001efa9 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs @@ -0,0 +1,24 @@ +using System; + +namespace LINGYUN.Abp.BlobManagement; + +public class BlobDownloadKeyCacheItem +{ + public string Url { get; set; } + public Guid BlobId { get; set; } + public BlobDownloadKeyCacheItem() + { + + } + + public BlobDownloadKeyCacheItem(Guid blobId, string url) + { + BlobId = blobId; + Url = url; + } + + public static string CalculateCacheKey(Guid blobId, string blobName) + { + return $"{blobId:N}{blobName.RemovePreFix("/")}"; + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs index f52b5ee62..68df23011 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs @@ -1,4 +1,7 @@ -using LINGYUN.Abp.BlobManagement.Settings; +using LINGYUN.Abp.BlobManagement.Features; +using LINGYUN.Abp.BlobManagement.Settings; +using LINGYUN.Abp.Features.LimitValidation; +using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using System; using System.IO; @@ -10,6 +13,7 @@ using Volo.Abp.Caching; using Volo.Abp.Content; using Volo.Abp.Domain.Services; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; using Volo.Abp.IO; using Volo.Abp.Settings; using Volo.Abp.Specifications; @@ -19,11 +23,13 @@ namespace LINGYUN.Abp.BlobManagement; public class BlobManager : DomainService { + private readonly IDistributedCache _blobDownloadKeyCache; private readonly IDistributedCache _blobDownloadCache; private readonly IDistributedEventBus _distributedEventBus; private readonly IMemoryCache _blobFileValidateCache; private readonly ISettingProvider _settingProvider; + private readonly IBlobContentTypeResolver _blobContentTypeResolver; private readonly IBlobProvider _blobProvider; private readonly IBlobRepository _blobRepository; private readonly IBlobContainerRepository _blobContainerRepository; @@ -36,7 +42,9 @@ public class BlobManager : DomainService IBlobContainerRepository blobContainerRepository, ICancellationTokenProvider cancellationTokenProvider, IDistributedEventBus distributedEventBus, + IDistributedCache blobDownloadKeyCache, IDistributedCache blobDownloadCache, + IBlobContentTypeResolver blobContentTypeResolver, IApplicationInfoAccessor applicationInfoAccessor, IMemoryCache blobFileValidateCache, ISettingProvider settingProvider) @@ -46,7 +54,9 @@ public class BlobManager : DomainService _blobContainerRepository = blobContainerRepository; _cancellationTokenProvider = cancellationTokenProvider; _distributedEventBus = distributedEventBus; + _blobDownloadKeyCache = blobDownloadKeyCache; _blobDownloadCache = blobDownloadCache; + _blobContentTypeResolver = blobContentTypeResolver; _applicationInfoAccessor = applicationInfoAccessor; _blobFileValidateCache = blobFileValidateCache; _settingProvider = settingProvider; @@ -183,11 +193,15 @@ public class BlobManager : DomainService } } + [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] + [RequiresLimitFeature( + BlobManagementFeatureNames.Blob.UploadLimit, + BlobManagementFeatureNames.Blob.UploadInterval, + LimitPolicy.Month)] public async virtual Task UploadBlobAsync( BlobContainer blobContainer, Blob blob, Stream stream, - string? contentType = null, string? compareMd5 = null) { await ValidateUploadFileAsync(blob.Name, stream.Length); @@ -204,7 +218,14 @@ public class BlobManager : DomainService blob.SetContentMd5(blobMd5); } - await _blobProvider.UploadBlobAsync(blobContainer.Name, blob.FullName, stream, GetCancellationToken()); + var contentType = await _blobContentTypeResolver.ResolveContentTypeAsync(blob.Name, stream); + + await _blobProvider.UploadBlobAsync( + blobContainer.Name, + blob.FullName, + stream, + contentType, + GetCancellationToken()); blob.SetProvider(_blobProvider.Name); blob.SetFileInfo(contentType, stream.Length); @@ -212,6 +233,7 @@ public class BlobManager : DomainService return blob; } + [RequiresFeature(BlobManagementFeatureNames.Blob.UploadFile)] public async virtual Task CreateChunkBlobAsync( string containerIdOrName, string name, @@ -285,6 +307,7 @@ public class BlobManager : DomainService // 多分片文件流合并上传 mergeFileStream.Seek(0, SeekOrigin.Begin); + await UploadBlobAsync(blobContainer, blob, mergeFileStream, compareMd5); } // 文件保存之后删除临时文件目录 @@ -299,6 +322,11 @@ public class BlobManager : DomainService } } + [RequiresFeature(BlobManagementFeatureNames.Blob.DownloadFile)] + [RequiresLimitFeature( + BlobManagementFeatureNames.Blob.DownloadLimit, + BlobManagementFeatureNames.Blob.DownloadInterval, + LimitPolicy.Month)] public async virtual Task DownloadBlobsync(Blob blob) { var containerName = await _blobContainerRepository.GetNameAsync(blob.ContainerId); @@ -306,6 +334,59 @@ public class BlobManager : DomainService return await DownloadBlobsync(containerName, blob.FullName); } + [RequiresFeature(BlobManagementFeatureNames.Blob.GenerateDownloadUrl)] + public async virtual Task GenerateDownloadUrlAsync( + BlobContainer blobContainer, + Blob blob, + string fallbackUrlPrefix) + { + var cacheKey = BlobDownloadKeyCacheItem.CalculateCacheKey(blob.Id, blob.FullName); + var cacheItem = await _blobDownloadKeyCache.GetAsync(cacheKey); + if (cacheItem == null) + { + var downloadUrlExpirySeconds = await _settingProvider.GetAsync( + BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds, + BlobManagementSettingNames.DefaultGenerateDownloadUrlExpirySeconds); + + var downloadUrl = await _blobProvider.GenerateDownloadUrlAsync( + blobContainer.Name, + blob.FullName, + TimeSpan.FromSeconds(downloadUrlExpirySeconds), + GetCancellationToken()); + + if (downloadUrl.IsNullOrWhiteSpace()) + { + // 特殊对象存储提供者(FileSystem)无法生成下载链接, 回退指定的请求Url前缀 + downloadUrl = fallbackUrlPrefix.EnsureEndsWith('/') + cacheKey; + } + + cacheItem = new BlobDownloadKeyCacheItem( + blob.Id, + downloadUrl); + + await _blobDownloadKeyCache.SetAsync( + cacheKey, + cacheItem, + new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(downloadUrlExpirySeconds), + }); + } + + return cacheItem.Url; + } + + public async virtual Task FindBlobByDownloadKeyAsync(string downloadKey) + { + var cacheItem = await _blobDownloadKeyCache.GetAsync(downloadKey); + if (cacheItem == null) + { + return null; + } + + return await _blobRepository.FindAsync(cacheItem.BlobId); + } + public virtual string GetBlobProvider() { return _blobProvider.Name; diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolver.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolver.cs new file mode 100644 index 000000000..8bab66334 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContentTypeResolver.cs @@ -0,0 +1,9 @@ +using System.IO; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.BlobManagement; + +public interface IBlobContentTypeResolver +{ + Task ResolveContentTypeAsync(string blobName, Stream blobStream); +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs index 72a7a708f..01a012279 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Threading; using System.Threading.Tasks; @@ -21,6 +22,12 @@ public interface IBlobProvider string blobName, CancellationToken cancellationToken = default); + Task GenerateDownloadUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + CancellationToken cancellationToken = default); + Task CreateFolderAsync( string containerName, string blobName, @@ -35,6 +42,7 @@ public interface IBlobProvider string containerName, string blobName, Stream stream, + string? contentType = null, CancellationToken cancellationToken = default); Task DeleteBlobAsync( diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs index 173590bbf..8fcbc8b0f 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs @@ -99,6 +99,16 @@ public class FileSystemBlobProvider : IBlobProvider return Task.FromResult(File.OpenRead(fileName)); } + public virtual Task GenerateDownloadUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + CancellationToken cancellationToken = default) + { + // 本地文件系统无需生成下载链接 + return Task.FromResult(null); + } + public virtual Task CreateFolderAsync( string containerName, string blobName, @@ -114,7 +124,8 @@ public class FileSystemBlobProvider : IBlobProvider public async virtual Task UploadBlobAsync( string containerName, string blobName, - Stream content, + Stream content, + string? contentType = null, CancellationToken cancellationToken = default) { var fileName = CalculateBlobName(NormalizeContainerName(containerName.RemovePostFix("/")), blobName); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/AbpBlobManagementHttpApiModule.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/AbpBlobManagementHttpApiModule.cs index d873970ab..2955c3b39 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/AbpBlobManagementHttpApiModule.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/AbpBlobManagementHttpApiModule.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.AspNetCore.VirtualFileSystem; using Volo.Abp.Modularity; namespace LINGYUN.Abp.BlobManagement; @@ -26,4 +27,17 @@ public class AbpBlobManagementHttpApiModule : AbpModule typeof(AbpBlobManagementApplicationContractsModule).Assembly); }); } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.ContentTypeMaps.TryAdd(".log", "text/plain"); + options.ContentTypeMaps.TryAdd(".text", "text/plain"); + }); + Configure(options => + { + options.BlobContentTypeResolvers.Add(new FileExtensionBlobContentTypeResolveContributor()); + }); + } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs index 559abbbf4..696f7d391 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs @@ -73,4 +73,18 @@ public class BlobController : BlobControllerBase, IBlobAppService { return _service.GetListAsync(input); } + + [HttpGet("{id}/generate-url")] + public virtual Task GenerateDownloadUrlAsync(Guid id) + { + return _service.GenerateDownloadUrlAsync(id); + } + + [HttpGet] + [Route("download/{Key}")] + [Route("download/t/{TenantId}/{Key}")] + public virtual Task DownloadAsync(BlobDownloadByKeyInput input) + { + return _service.DownloadAsync(input); + } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/FileExtensionBlobContentTypeResolveContributor.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/FileExtensionBlobContentTypeResolveContributor.cs new file mode 100644 index 000000000..c7f80cc8c --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/FileExtensionBlobContentTypeResolveContributor.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.BlobManagement; + +public class FileExtensionBlobContentTypeResolveContributor : IBlobContentTypeResolveContributor +{ + public string Name => "FileExtension"; + public int Priority => 0; + + public virtual Task ResolveAsync(BlobContentTypeResolveContext context) + { + var contentTypeProvider = context.ServiceProvider.GetService(); + if (contentTypeProvider != null && + contentTypeProvider.TryGetContentType(context.BlobName, out var contentType) && + !contentType.IsNullOrWhiteSpace()) + { + context.Success(contentType); + } + return Task.CompletedTask; + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xml b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xsd b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN.Abp.BlobManagement.MimeCheck.csproj b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN.Abp.BlobManagement.MimeCheck.csproj new file mode 100644 index 000000000..3d93dbe81 --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN.Abp.BlobManagement.MimeCheck.csproj @@ -0,0 +1,25 @@ + + + + + + + net10.0 + LINGYUN.Abp.BlobManagement.MimeCheck + LINGYUN.Abp.BlobManagement.MimeCheck + false + false + false + enable + + + + + + + + + + + + diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/AbpBlobManagementMimeCheckModule.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/AbpBlobManagementMimeCheckModule.cs new file mode 100644 index 000000000..f39f98c4b --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/AbpBlobManagementMimeCheckModule.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BlobManagement.MimeCheck; + +[DependsOn(typeof(AbpBlobManagementDomainModule))] +public class AbpBlobManagementMimeCheckModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.BlobContentTypeResolvers.Add(new MimeCheckBlobContentTypeResolveContributor()); + }); + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/MimeCheckBlobContentTypeResolveContributor.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/MimeCheckBlobContentTypeResolveContributor.cs new file mode 100644 index 000000000..16a68583c --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN/Abp/BlobManagement/MimeCheck/MimeCheckBlobContentTypeResolveContributor.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using MimeCheck.Detection; +using MimeCheck.Validation; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.BlobManagement.MimeCheck; + +public class MimeCheckBlobContentTypeResolveContributor : IBlobContentTypeResolveContributor +{ + public string Name => "MimeCheck"; + public int Priority => 200; + + public async virtual Task ResolveAsync(BlobContentTypeResolveContext context) + { + try + { + var streamResult = await MimeValidator.DetectAsync(context.Stream); + if (!streamResult.MimeType.IsNullOrWhiteSpace() && + !string.Equals(streamResult.MimeType, DetectionResult.Unknown.MimeType)) + { + context.Success(streamResult.MimeType); + } + } + catch (Exception ex) + { + context.ServiceProvider + .GetService>() + ?.LogWarning("Failed to decetion the blob mime type: {message}!", ex.Message); + } + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs index bc449401f..69414c0c9 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring.Minio; using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; namespace LINGYUN.Abp.BlobManagement.Minio; @@ -19,17 +20,20 @@ public class MinioBlobProvider : IBlobProvider public const string ProviderName = "Minio"; public string Name => ProviderName; + protected IClock Clock { get; } protected ICurrentTenant CurrentTenant { get; } protected IHttpClientFactory HttpClientFactory { get; } protected MinioBlobNamingNormalizer BlobNamingNormalizer { get; } protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } public MinioBlobProvider( + IClock clock, ICurrentTenant currentTenant, IHttpClientFactory httpClientFactory, MinioBlobNamingNormalizer blobNamingNormalizer, IBlobContainerConfigurationProvider configurationProvider) { + Clock = clock; CurrentTenant = currentTenant; HttpClientFactory = httpClientFactory; BlobNamingNormalizer = blobNamingNormalizer; @@ -101,6 +105,29 @@ public class MinioBlobProvider : IBlobProvider string containerName, string blobName, CancellationToken cancellationToken = default) + { + var configuration = GetBlobConfiguration(); + + var downloadUrl = await GenerateDownloadUrlAsync( + containerName, + blobName, + TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), + cancellationToken); + if (downloadUrl.IsNullOrWhiteSpace()) + { + return null; + } + + var httpClient = HttpClientFactory.CreateMinioHttpClient(); + + return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + } + + public async virtual Task GenerateDownloadUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + CancellationToken cancellationToken = default) { var client = GetMinioClient(); var bucket = NormalizeContainerName(containerName); @@ -111,17 +138,11 @@ public class MinioBlobProvider : IBlobProvider return null; } - var configuration = GetBlobConfiguration(); - - var downloadUrl = await client.PresignedGetObjectAsync( - new PresignedGetObjectArgs() - .WithBucket(bucket) - .WithObject(objectName) - .WithExpiry(configuration.PresignedGetExpirySeconds)); - - var httpClient = HttpClientFactory.CreateMinioHttpClient(); - - return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + return await client.PresignedGetObjectAsync( + new PresignedGetObjectArgs() + .WithBucket(bucket) + .WithObject(objectName) + .WithExpiry(expiration.TotalSeconds.To())); } public virtual Task CreateFolderAsync( @@ -136,7 +157,8 @@ public class MinioBlobProvider : IBlobProvider public async virtual Task UploadBlobAsync( string containerName, string blobName, - Stream content, + Stream content, + string? contentType = null, CancellationToken cancellationToken = default) { var client = GetMinioClient(); @@ -145,12 +167,17 @@ public class MinioBlobProvider : IBlobProvider await CreateBucketIfNotExists(client, bucket); - await client.PutObjectAsync(new PutObjectArgs() + var putObjectArgs = new PutObjectArgs() .WithBucket(bucket) .WithObject(objectName) .WithStreamData(content) - .WithObjectSize(content.Length), - cancellationToken); + .WithObjectSize(content.Length); + if (!contentType.IsNullOrWhiteSpace()) + { + putObjectArgs.WithContentType(contentType); + } + + await client.PutObjectAsync(putObjectArgs, cancellationToken); } protected virtual IMinioClient GetMinioClient() diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs index 7e9425a50..1a6cfa5e1 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs @@ -51,6 +51,11 @@ public class BlobManagementSettingAppService : ApplicationService, IBlobManageme var ossObjectSetting = ossSettingGroup.AddSetting(L["DisplayName:Blobs"], L["DisplayName:Blobs"]); + ossObjectSetting.AddDetail( + await SettingDefinitionManager.GetAsync(BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds), + StringLocalizerFactory, + await SettingManager.GetOrNullAsync(BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds, providerName, providerKey), + ValueType.Number); ossObjectSetting.AddDetail( await SettingDefinitionManager.GetAsync(BlobManagementSettingNames.FileLimitLength), StringLocalizerFactory, diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs index e17691b9c..671525b8d 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs @@ -10,9 +10,9 @@ using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Volo.Abp; using Volo.Abp.BlobStoring; using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; namespace LINGYUN.Abp.BlobManagement.Tencent; @@ -21,6 +21,7 @@ public class TencentBlobProvider : IBlobProvider public const string ProviderName = "TencentCloud"; public string Name => ProviderName; + protected IClock Clock { get; } protected IConfiguration Configuration { get; } protected ICurrentTenant CurrentTenant { get; } protected ICosClientFactory CosClientFactory { get; } @@ -29,6 +30,7 @@ public class TencentBlobProvider : IBlobProvider protected IBlobContainerConfigurationProvider ConfigurationProvider { get; } public TencentBlobProvider( + IClock clock, IConfiguration configuration, ICurrentTenant currentTenant, ICosClientFactory cosClientFactory, @@ -36,6 +38,7 @@ public class TencentBlobProvider : IBlobProvider TencentBlobNamingNormalizer blobNamingNormalizer, IBlobContainerConfigurationProvider configurationProvider) { + Clock = clock; Configuration = configuration; CurrentTenant = currentTenant; CosClientFactory = cosClientFactory; @@ -97,6 +100,29 @@ public class TencentBlobProvider : IBlobProvider string containerName, string blobName, CancellationToken cancellationToken = default) + { + var configuration = await GetBlobConfiguration(); + + var downloadUrl = await GenerateDownloadUrlAsync( + containerName, + blobName, + TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), + cancellationToken); + if (downloadUrl.IsNullOrWhiteSpace()) + { + return null; + } + + var httpClient = HttpClientFactory.CreateTencentHttpClient(); + + return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + } + + public async virtual Task GenerateDownloadUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + CancellationToken cancellationToken = default) { var client = await CreateClientAsync(); var bucket = NormalizeContainerName(containerName); @@ -108,8 +134,6 @@ public class TencentBlobProvider : IBlobProvider } var configuration = await GetBlobConfiguration(); - var blobProviderConfig = Configuration.GetSection($"BlobManagement:{ProviderName}"); - // See: https://cloud.tencent.com/document/product/436/47238 var preSignatureStruct = new PreSignatureStruct { @@ -119,16 +143,12 @@ public class TencentBlobProvider : IBlobProvider key = objectName, //对象键 httpMethod = "GET", //HTTP 请求方法 isHttps = true, //生成 HTTPS 请求 URL - signDurationSecond = blobProviderConfig.GetValue("SignDurationSecond", 600), //请求签名时间 + signDurationSecond = expiration.TotalSeconds.To(), //请求签名时间 headers = null, //签名中需要校验的 header queryParameters = null //签名中需要校验的 URL 中请求参数 }; - var downloadUrl = client.GenerateSignURL(preSignatureStruct); - - var httpClient = HttpClientFactory.CreateTencentHttpClient(); - - return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + return client.GenerateSignURL(preSignatureStruct); } public virtual Task CreateFolderAsync( @@ -144,7 +164,8 @@ public class TencentBlobProvider : IBlobProvider public async virtual Task UploadBlobAsync( string containerName, string blobName, - Stream content, + Stream content, + string? contentType = null, CancellationToken cancellationToken = default) { var client = await CreateClientAsync(); @@ -153,7 +174,13 @@ public class TencentBlobProvider : IBlobProvider CreateBucketIfNotExists(client, bucket); - client.PutObject(new PutObjectRequest(bucket, objectName, content)); + var putObjectRequest = new PutObjectRequest(bucket, objectName, content); + if (!contentType.IsNullOrWhiteSpace()) + { + putObjectRequest.SetRequestHeader("Content-Type", contentType); + } + + client.PutObject(putObjectRequest); } protected async virtual Task CreateClientAsync() diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index 5537e2c55..e04cb7fee 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -151,6 +151,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index 287123617..fdd8aee01 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -1,3 +1,4 @@ +using LINGYUN.Abp.BlobManagement.MimeCheck; using LINGYUN.Abp.Exporter.MiniSoftware; using LINGYUN.Abp.Notifications.Calendar; @@ -130,6 +131,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpBlobManagementMinioModule), // 对象存储模块 腾讯云 typeof(AbpBlobManagementTencentModule), + // 对象存储模块 MimeCheck扩展 + typeof(AbpBlobManagementMimeCheckModule), // 对象存储模块 应用服务 typeof(AbpBlobManagementDomainModule), // 对象存储模块 控制器 From 6d725513a8c869dea8eea524e80ea5a3c60fa85e Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 28 May 2026 09:34:03 +0800 Subject: [PATCH 15/40] feat(aliyun): Optimize the integration module of Alibaba Cloud - Use Alibaba Cloud v2 SDK --- Directory.Packages.props | 4 + .../LINGYUN.Abp.Aliyun.csproj | 2 +- .../LINGYUN/Abp/Aliyun/AcsClientFactory.cs | 34 ----- .../AliyunBasicSessionCredentialsCacheItem.cs | 11 +- .../LINGYUN/Abp/Aliyun/AliyunClientFactory.cs | 97 +++++++++----- .../LINGYUN/Abp/Aliyun/IAcsClientFactory.cs | 14 --- .../Aliyun/Settings/AliyunSettingProvider.cs | 2 +- .../LINGYUN.Abp.BlobStoring.Aliyun.csproj | 2 +- .../BlobStoring/Aliyun/AliyunBlobProvider.cs | 109 ++++++++++------ .../Aliyun/AliyunBlobProviderConfiguration.cs | 19 ++- .../AliyunBlobProviderConfigurationNames.cs | 8 ++ .../BlobStoring/Aliyun/IOssClientFactory.cs | 6 +- .../BlobStoring/Aliyun/OssClientFactory.cs | 86 +++++++++---- .../LINGYUN.Abp.Sms.Aliyun.csproj | 2 + .../LINGYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs | 119 +++++++----------- .../Abp/Sms/Aliyun/DypnsClientFactory.cs | 41 ++++++ .../Abp/Sms/Aliyun/DysmsClientFactory.cs | 38 ++++++ .../Abp/Sms/Aliyun/IDypnsClientFactory.cs | 13 ++ .../Abp/Sms/Aliyun/IDysmsClientFactory.cs | 13 ++ 19 files changed, 390 insertions(+), 230 deletions(-) delete mode 100644 aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AcsClientFactory.cs delete mode 100644 aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/IAcsClientFactory.cs create mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DypnsClientFactory.cs create mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DysmsClientFactory.cs create mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDypnsClientFactory.cs create mode 100644 aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDysmsClientFactory.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index b9d54b3e0..7ef269c33 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -333,6 +333,10 @@ + + + + diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj index c9604faa5..fd6b3232a 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj @@ -25,7 +25,7 @@ - + diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AcsClientFactory.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AcsClientFactory.cs deleted file mode 100644 index 4401aee25..000000000 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AcsClientFactory.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Aliyun.Acs.Core; -using Aliyun.Acs.Core.Auth; -using Aliyun.Acs.Core.Profile; -using LINGYUN.Abp.Aliyun.Features; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Features; -using Volo.Abp.Settings; - -namespace LINGYUN.Abp.Aliyun; - -[RequiresFeature(AliyunFeatureNames.Enable)] -public class AcsClientFactory : AliyunClientFactory, IAcsClientFactory, ITransientDependency -{ - public AcsClientFactory( - ISettingProvider settingProvider, - IDistributedCache cache) - : base(settingProvider, cache) - { - } - - protected override IAcsClient GetClient(string regionId, string accessKeyId, string accessKeySecret) - { - return new DefaultAcsClient( - DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret)); - } - - protected override IAcsClient GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken) - { - var profile = DefaultProfile.GetProfile(regionId); - var credentials = new BasicSessionCredentials(accessKeyId, accessKeySecret, securityToken); - return new DefaultAcsClient(profile, credentials); - } -} diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunBasicSessionCredentialsCacheItem.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunBasicSessionCredentialsCacheItem.cs index 41630d221..8533d6ed0 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunBasicSessionCredentialsCacheItem.cs +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunBasicSessionCredentialsCacheItem.cs @@ -5,26 +5,21 @@ namespace LINGYUN.Abp.Aliyun; [Serializable] public class AliyunBasicSessionCredentialsCacheItem { - private readonly static string _cacheKey; - public static string CacheKey => _cacheKey; public string AccessKeyId { get; set; } public string AccessKeySecret { get; set; } public string SecurityToken { get; set; } - - static AliyunBasicSessionCredentialsCacheItem() - { - _cacheKey = Guid.NewGuid().ToString("N"); - } + public DateTime? Expiration { get; set; } public AliyunBasicSessionCredentialsCacheItem() { } - public AliyunBasicSessionCredentialsCacheItem(string accessKeyId, string accessKeySecret, string securityToken) + public AliyunBasicSessionCredentialsCacheItem(string accessKeyId, string accessKeySecret, string securityToken, DateTime? expiration = null) { AccessKeyId = accessKeyId; AccessKeySecret = accessKeySecret; SecurityToken = securityToken; + Expiration = expiration; } } diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs index df800cb11..f87b007ca 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs @@ -1,14 +1,12 @@ -using Aliyun.Acs.Core; -using Aliyun.Acs.Core.Auth.Sts; -using Aliyun.Acs.Core.Http; -using Aliyun.Acs.Core.Profile; -using LINGYUN.Abp.Aliyun.Settings; +using LINGYUN.Abp.Aliyun.Settings; using Microsoft.Extensions.Caching.Distributed; using System; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Caching; using Volo.Abp.Settings; +using OpenApiConfig = AlibabaCloud.OpenApiClient.Models.Config; +using StsClient = AlibabaCloud.SDK.Sts20150401.Client; namespace LINGYUN.Abp.Aliyun; @@ -42,19 +40,33 @@ public abstract class AliyunClientFactory { var cacheItem = await GetCacheItemAsync(accessKey, accessKeySecret, regionId); - return GetSecurityTokenClient(regionId, cacheItem.AccessKeyId, cacheItem.AccessKeySecret, cacheItem.SecurityToken); + return GetSecurityTokenClient( + regionId, + cacheItem.AccessKeyId, + cacheItem.AccessKeySecret, + cacheItem.SecurityToken, + cacheItem.Expiration); } return GetClient(regionId, accessKey, accessKeySecret); } - protected abstract TClient GetClient(string regionId, string accessKeyId, string accessKeySecret); + protected abstract TClient GetClient( + string regionId, + string accessKeyId, + string accessKeySecret); - protected abstract TClient GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken); + protected abstract TClient GetSecurityTokenClient( + string regionId, + string accessKeyId, + string accessKeySecret, + string securityToken, + DateTime? expiration = null); protected async virtual Task GetCacheItemAsync(string accessKeyId, string accessKeySecret, string regionId) { - var cacheItem = await Cache.GetAsync(AliyunBasicSessionCredentialsCacheItem.CacheKey); + var cacheKey = $"{accessKeyId}:{accessKeySecret}".ToMd5(); + var cacheItem = await Cache.GetAsync(cacheKey); if (cacheItem == null) { var roleArn = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.RamRoleArn); @@ -64,30 +76,41 @@ public abstract class AliyunClientFactory var policy = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Authorization.Policy); var durationSeconds = await SettingProvider.GetAsync(AliyunSettingNames.Authorization.DurationSeconds, 3000); - var profile = DefaultProfile.GetProfile(regionId, accessKeyId, accessKeySecret); - var request = new AssumeRoleRequest - { - AcceptFormat = FormatType.JSON, - RoleArn = roleArn, - RoleSessionName = roleSession, - DurationSeconds = durationSeconds, - Policy = policy.IsNullOrWhiteSpace() ? null : policy - }; + var stsClient = new StsClient( + new OpenApiConfig + { + RegionId = regionId, + AccessKeyId = accessKeyId, + AccessKeySecret = accessKeySecret, + }); - var client = new DefaultAcsClient(profile); - var response = client.GetAcsResponse(request); + var assumeRoleResponse = await stsClient.AssumeRoleAsync( + new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest + { + RoleArn = roleArn, + RoleSessionName = roleSession, + DurationSeconds = durationSeconds, + Policy = policy.IsNullOrWhiteSpace() ? null : policy, + }); cacheItem = new AliyunBasicSessionCredentialsCacheItem( - response.Credentials.AccessKeyId, - response.Credentials.AccessKeySecret, - response.Credentials.SecurityToken); + assumeRoleResponse.Body.Credentials.AccessKeyId, + assumeRoleResponse.Body.Credentials.AccessKeySecret, + assumeRoleResponse.Body.Credentials.SecurityToken); + + var expirationTimeSpan = TimeSpan.FromSeconds(durationSeconds - 10); + if (DateTime.TryParse(assumeRoleResponse.Body.Credentials.Expiration, out var expiration)) + { + cacheItem.Expiration = expiration; + expirationTimeSpan = new TimeSpan(expiration.AddSeconds(-10).Ticks); + } await Cache.SetAsync( - AliyunBasicSessionCredentialsCacheItem.CacheKey, + cacheKey, cacheItem, new DistributedCacheEntryOptions { - AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(durationSeconds - 10) + AbsoluteExpirationRelativeToNow = expirationTimeSpan, }); } @@ -122,13 +145,29 @@ public abstract class AliyunClientFactory : AliyunClien { var cacheItem = await GetCacheItemAsync(accessKey, accessKeySecret, regionId); - return GetSecurityTokenClient(configuration, regionId, cacheItem.AccessKeyId, cacheItem.AccessKeySecret, cacheItem.SecurityToken); + return GetSecurityTokenClient( + configuration, + regionId, + cacheItem.AccessKeyId, + cacheItem.AccessKeySecret, + cacheItem.SecurityToken, + cacheItem.Expiration); } return GetClient(configuration, regionId, accessKey, accessKeySecret); } - protected abstract TClient GetClient(TConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret); - - protected abstract TClient GetSecurityTokenClient(TConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret, string securityToken); + protected abstract TClient GetClient( + TConfiguration configuration, + string regionId, + string accessKeyId, + string accessKeySecret); + + protected abstract TClient GetSecurityTokenClient( + TConfiguration configuration, + string regionId, + string accessKeyId, + string accessKeySecret, + string securityToken, + DateTime? expiration = null); } diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/IAcsClientFactory.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/IAcsClientFactory.cs deleted file mode 100644 index bf81b77c1..000000000 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/IAcsClientFactory.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Aliyun.Acs.Core; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.Aliyun; - -public interface IAcsClientFactory -{ - /// - /// 构造一个通用的Acs客户端调用 - /// 通过CommonRequest调用可以不需要集成其他SDK包 - /// - /// - Task CreateAsync(); -} diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs index 5e5f98805..955594a6a 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs @@ -79,7 +79,7 @@ public class AliyunSettingProvider : SettingDefinitionProvider TenantSettingValueProvider.ProviderName), new SettingDefinition( AliyunSettingNames.Authorization.RegionId, - defaultValue: "oss-cn-hangzhou", + defaultValue: "cn-hangzhou", displayName: L("DisplayName:RegionId"), description: L("Description:RegionId"), isVisibleToClients: false diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj index 59822d893..7f8460f95 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj @@ -15,7 +15,7 @@ - + diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs index 0064ce2cc..af8bd175d 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs @@ -1,29 +1,33 @@ -using Aliyun.OSS; +using AlibabaCloud.OSS.V2; +using AlibabaCloud.OSS.V2.Models; using LINGYUN.Abp.Aliyun.Features; using Microsoft.Extensions.DependencyInjection; using System; -using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading.Tasks; using Volo.Abp.BlobStoring; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; +using Volo.Abp.Timing; namespace LINGYUN.Abp.BlobStoring.Aliyun; [RequiresFeature(AliyunFeatureNames.BlobStoring.Enable)] public class AliyunBlobProvider : BlobProviderBase, ITransientDependency { + protected IClock Clock { get; } protected IOssClientFactory OssClientFactory { get; } protected IHttpClientFactory HttpClientFactory { get; } protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; } public AliyunBlobProvider( + IClock clock, IOssClientFactory ossClientFactory, IHttpClientFactory httpClientFactory, IAliyunBlobNameCalculator aliyunBlobNameCalculator) { + Clock = clock; OssClientFactory = ossClientFactory; HttpClientFactory = httpClientFactory; AliyunBlobNameCalculator = aliyunBlobNameCalculator; @@ -36,7 +40,14 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency if (await BlobExistsAsync(ossClient, args, blobName)) { - return ossClient.DeleteObject(GetBucketName(args), blobName).DeleteMarker; + var deleteObjectRes = await ossClient.DeleteObjectAsync( + new DeleteObjectRequest + { + Bucket = GetBucketName(args), + Key = blobName, + }, + cancellationToken: args.CancellationToken); + return deleteObjectRes.DeleteMarker == true; } return false; @@ -60,11 +71,27 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency return null; } - var downloadUri = ossClient.GeneratePresignedUri(GetBucketName(args), blobName); - - var httpClient = HttpClientFactory.CreateAliyunHttpClient(); - - return await httpClient.GetStreamAsync(downloadUri, args.CancellationToken); + var result = await ossClient.GetObjectAsync( + new GetObjectRequest + { + Bucket = GetBucketName(args), + Key = blobName, + }); + return result.Body; + + // TODO: 阿里云sdk预签名不可用[2026/05/23] + //var configuration = args.Configuration.GetAliyunConfiguration(); + //var presignResult = ossClient.Presign( + // new GetObjectRequest + // { + // Bucket = GetBucketName(args), + // Key = blobName, + // }, + // Clock.Now.AddSeconds(configuration.PresignedGetExpirySeconds)); + + //var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + + //return await httpClient.GetStreamAsync(presignResult.Url, args.CancellationToken); } public override async Task SaveAsync(BlobProviderSaveArgs args) @@ -76,7 +103,7 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency // 先检查Bucket if (configuration.CreateBucketIfNotExists) { - await CreateBucketIfNotExists(ossClient, args, configuration.CreateBucketReferer); + await CreateBucketIfNotExists(ossClient, args, configuration.CreateBucketAcl); } var bucketName = GetBucketName(args); @@ -92,60 +119,70 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency else { // 删除原文件 - ossClient.DeleteObject(bucketName, blobName); + await ossClient.DeleteObjectAsync( + new DeleteObjectRequest + { + Bucket = bucketName, + Key = blobName, + }, + cancellationToken: args.CancellationToken); } } // 保存 - ossClient.PutObject(bucketName, blobName, args.BlobStream); + await ossClient.PutObjectAsync( + new PutObjectRequest + { + Bucket = bucketName, + Key = blobName, + Body = args.BlobStream, + }, + cancellationToken: args.CancellationToken); } - protected async virtual Task GetOssClientAsync(BlobProviderArgs args) + protected async virtual Task GetOssClientAsync(BlobProviderArgs args) { - var ossClient = await OssClientFactory.CreateAsync(); - return ossClient; + return await OssClientFactory.CreateAsync(); } - protected async virtual Task CreateBucketIfNotExists(IOss ossClient, BlobProviderArgs args, IList refererList = null) + protected async virtual Task CreateBucketIfNotExists(Client ossClient, BlobProviderArgs args, BucketAclType? bucketAcl = null) { - if (! await BucketExistsAsync(ossClient, args)) + if (!await BucketExistsAsync(ossClient, args)) { var bucketName = GetBucketName(args); - var request = new CreateBucketRequest(bucketName) - { - //设置存储空间访问权限ACL。 - ACL = CannedAccessControlList.PublicReadWrite, - //设置数据容灾类型。 - DataRedundancyType = DataRedundancyType.ZRS - }; - - ossClient.CreateBucket(request); + await ossClient.PutBucketAsync( + new PutBucketRequest + { + Bucket = bucketName, + }, + cancellationToken: args.CancellationToken); - if (refererList != null && refererList.Count > 0) + if (bucketAcl.HasValue) { - var srq = new SetBucketRefererRequest(bucketName, refererList); - ossClient.SetBucketReferer(srq); + await ossClient.PutBucketAclAsync( + new PutBucketAclRequest + { + Bucket = bucketName, + Acl = bucketAcl.Value.GetString(), + }, + cancellationToken: args.CancellationToken); } } } - private async Task BlobExistsAsync(IOss ossClient, BlobProviderArgs args, string blobName) + private async Task BlobExistsAsync(Client ossClient, BlobProviderArgs args, string blobName) { var bucketExists = await BucketExistsAsync(ossClient, args); if (bucketExists) { - var objectExists = ossClient.DoesObjectExist(GetBucketName(args), blobName); - - return objectExists; + return await ossClient.IsObjectExistAsync(GetBucketName(args), blobName, cancellationToken: args.CancellationToken); } return false; } - private Task BucketExistsAsync(IOss ossClient, BlobProviderArgs args) + private async Task BucketExistsAsync(Client ossClient, BlobProviderArgs args) { - var bucketExists = ossClient.DoesBucketExist(GetBucketName(args)); - - return Task.FromResult(bucketExists); + return await ossClient.IsBucketExistAsync(GetBucketName(args), args.CancellationToken); } private static string GetBucketName(BlobProviderArgs args) diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs index d7efa95a4..2401174e1 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using AlibabaCloud.OSS.V2.Models; +using System.Collections.Generic; using Volo.Abp.BlobStoring; namespace LINGYUN.Abp.BlobStoring.Aliyun; @@ -14,6 +15,13 @@ public class AliyunBlobProviderConfiguration set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.BucketName, value); } /// + /// 跳过服务器证书验证 + /// + public bool InsecureSkipVerify { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.InsecureSkipVerify, false); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.InsecureSkipVerify, value); + } + /// /// 命名空间不存在是否创建 /// public bool CreateBucketIfNotExists @@ -22,11 +30,18 @@ public class AliyunBlobProviderConfiguration set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, value); } /// + /// 创建命名空间时的Acl + /// + public BucketAclType? CreateBucketAcl { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketAcl); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketAcl, value); + } + /// /// 创建命名空间时防盗链列表 /// public List CreateBucketReferer { - get => _containerConfiguration.GetConfiguration>(AliyunBlobProviderConfigurationNames.CreateBucketReferer); + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketReferer, new List()); set { if (value == null) diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs index e3e0c9221..d0bc9f7a7 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs @@ -11,6 +11,10 @@ public static class AliyunBlobProviderConfigurationNames /// public const string BucketName = "Aliyun:OSS:BucketName"; /// + /// 跳过服务器证书验证 + /// + public const string InsecureSkipVerify = "Aliyun:OSS:InsecureSkipVerify"; + /// /// 命名空间不存在是否创建 /// public const string CreateBucketIfNotExists = "Aliyun:OSS:CreateBucketIfNotExists"; @@ -19,6 +23,10 @@ public static class AliyunBlobProviderConfigurationNames /// public const string CreateBucketReferer = "Aliyun:OSS:CreateBucketReferer"; /// + /// 创建命名空间时的Acl + /// + public const string CreateBucketAcl = "Aliyun:OSS:CreateBucketAcl"; + /// /// 生成预签名Uri的过期时间(s) /// public const string PresignedGetExpirySeconds = "Aliyun:OSS:PresignedGetExpirySeconds"; diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IOssClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IOssClientFactory.cs index 6a4ccd6fa..7dea3e3d5 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IOssClientFactory.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IOssClientFactory.cs @@ -1,4 +1,4 @@ -using Aliyun.OSS; +using AlibabaCloud.OSS.V2; using System.Threading.Tasks; namespace LINGYUN.Abp.BlobStoring.Aliyun; @@ -9,11 +9,11 @@ public interface IOssClientFactory /// 构建Oss客户端 /// /// - Task CreateAsync(); + Task CreateAsync(); /// /// 构建Oss客户端 /// /// /// - Task CreateAsync(AliyunBlobProviderConfiguration configuration); + Task CreateAsync(AliyunBlobProviderConfiguration configuration); } diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs index 9388454f0..6fc4da256 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs @@ -1,12 +1,14 @@ -using Aliyun.OSS; +using AlibabaCloud.OSS.V2; +using AlibabaCloud.OSS.V2.Credentials; using LINGYUN.Abp.Aliyun; +using System; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Settings; namespace LINGYUN.Abp.BlobStoring.Aliyun; -public class OssClientFactory : AliyunClientFactory, IOssClientFactory, ITransientDependency +public class OssClientFactory : AliyunClientFactory, IOssClientFactory, ITransientDependency { public OssClientFactory( ISettingProvider settingProvider, @@ -22,12 +24,22 @@ public class OssClientFactory : AliyunClientFactory /// /// - protected override IOss GetClient(string regionId, string accessKeyId, string accessKeySecret) + protected override Client GetClient(string regionId, string accessKeyId, string accessKeySecret) { - return new OssClient( - regionId, - accessKeyId, - accessKeySecret); + + return new Client( + new Configuration + { + Region = regionId, + CredentialsProvider = new CredentialsProviderFunc(() => + { + return new Credentials(accessKeyId, accessKeySecret); + }), + }); + //return new OssClient( + // regionId, + // accessKeyId, + // accessKeySecret); } /// @@ -38,12 +50,18 @@ public class OssClientFactory : AliyunClientFactory /// /// - protected override IOss GetClient(AliyunBlobProviderConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret) + protected override Client GetClient(AliyunBlobProviderConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret) { - return new OssClient( - regionId, - accessKeyId, - accessKeySecret); + return new Client( + new Configuration + { + Region = regionId, + CredentialsProvider = new CredentialsProviderFunc(() => + { + return new Credentials(accessKeyId, accessKeySecret); + }), + InsecureSkipVerify = configuration.InsecureSkipVerify, + }); } /// @@ -54,13 +72,22 @@ public class OssClientFactory : AliyunClientFactory /// /// - protected override IOss GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken) + protected override Client GetSecurityTokenClient( + string regionId, + string accessKeyId, + string accessKeySecret, + string securityToken, + DateTime? expiration = null) { - return new OssClient( - regionId, - accessKeyId, - accessKeySecret, - securityToken); + return new Client( + new Configuration + { + Region = regionId, + CredentialsProvider = new CredentialsProviderFunc(() => + { + return new Credentials(accessKeyId, accessKeySecret, securityToken, expiration); + }), + }); } /// /// 通过用户安全令牌构建Oss客户端 @@ -71,12 +98,23 @@ public class OssClientFactory : AliyunClientFactory /// /// - protected override IOss GetSecurityTokenClient(AliyunBlobProviderConfiguration configuration, string regionId, string accessKeyId, string accessKeySecret, string securityToken) + protected override Client GetSecurityTokenClient( + AliyunBlobProviderConfiguration configuration, + string regionId, + string accessKeyId, + string accessKeySecret, + string securityToken, + DateTime? expiration = null) { - return new OssClient( - regionId, - accessKeyId, - accessKeySecret, - securityToken); + return new Client( + new Configuration + { + Region = regionId, + CredentialsProvider = new CredentialsProviderFunc(() => + { + return new Credentials(accessKeyId, accessKeySecret, securityToken, expiration); + }), + InsecureSkipVerify = configuration.InsecureSkipVerify, + }); } } diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj index a2d642c68..aabe2f950 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj +++ b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj @@ -21,6 +21,8 @@ + + diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs index 2e749fb0e..745422f5f 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs @@ -1,14 +1,11 @@ -using Aliyun.Acs.Core; -using Aliyun.Acs.Core.Exceptions; -using Aliyun.Acs.Core.Http; -using LINGYUN.Abp.Aliyun; +using AlibabaCloud.SDK.Dypnsapi20170525.Models; +using AlibabaCloud.SDK.Dysmsapi20170525.Models; using LINGYUN.Abp.Aliyun.Features; using LINGYUN.Abp.Aliyun.Settings; using LINGYUN.Abp.Features.LimitValidation; using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; -using System.Text; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.DependencyInjection; @@ -30,17 +27,20 @@ public class AliyunSmsSender : ISmsSender, IAliyunSmsVerifyCodeSender protected IJsonSerializer JsonSerializer { get; } protected ISettingProvider SettingProvider { get; } protected IServiceProvider ServiceProvider { get; } - protected IAcsClientFactory AcsClientFactory { get; } + protected IDypnsClientFactory DypnsClientFactory { get; } + protected IDysmsClientFactory DysmsClientFactory { get; } public AliyunSmsSender( IJsonSerializer jsonSerializer, ISettingProvider settingProvider, IServiceProvider serviceProvider, - IAcsClientFactory acsClientFactory) + IDypnsClientFactory dypnsClientFactory, + IDysmsClientFactory dysmsClientFactory) { JsonSerializer = jsonSerializer; SettingProvider = settingProvider; ServiceProvider = serviceProvider; - AcsClientFactory = acsClientFactory; + DypnsClientFactory = dypnsClientFactory; + DysmsClientFactory = dysmsClientFactory; } [RequiresLimitFeature( @@ -74,41 +74,23 @@ public class AliyunSmsSender : ISmsSender, IAliyunSmsVerifyCodeSender Check.NotNullOrWhiteSpace(action, AliyunSettingNames.Sms.ActionName); Check.NotNullOrWhiteSpace(version, AliyunSettingNames.Sms.Version); - var request = new CommonRequest - { - Method = MethodType.POST, - Domain = domain, - Action = action, - Version = version - }; + var request = new SendSmsRequest(); + await TryAddTemplateCodeAsync(request, smsMessage); await TryAddSignNameAsync(request, smsMessage); await TryAddSendPhoneAsync(request, smsMessage); - TryAddTemplateParam(request, smsMessage); - try + + var dysmsClient = await DysmsClientFactory.CreateAsync(); + var response = await dysmsClient.SendSmsAsync(request); + if (!string.Equals(response.Body.Code, "OK", StringComparison.CurrentCultureIgnoreCase)) { - var client = await AcsClientFactory.CreateAsync(); - var response = client.GetCommonResponse(request); - var responseContent = Encoding.Default.GetString(response.HttpResponse.Content); - var aliyunResponse = JsonSerializer.Deserialize(responseContent); - if (!aliyunResponse.IsSuccess()) + if (await SettingProvider.IsTrueAsync(AliyunSettingNames.Sms.VisableErrorToClient)) { - if (await SettingProvider.IsTrueAsync(AliyunSettingNames.Sms.VisableErrorToClient)) - { - throw new UserFriendlyException(aliyunResponse.Code, aliyunResponse.Message); - } - throw new AliyunSmsException(aliyunResponse.Code, $"Text message sending failed, code:{aliyunResponse.Code}, message:{aliyunResponse.Message}!"); + throw new UserFriendlyException(response.Body.Code, response.Body.Message); } - } - catch(ServerException se) - { - throw new AliyunSmsException(se.ErrorCode, $"Sending text messages to aliyun server is abnormal,type: {se.ErrorType}, error: {se.ErrorMessage}"); - } - catch(ClientException ce) - { - throw new AliyunSmsException(ce.ErrorCode, $"A client exception occurred in sending SMS messages,type: {ce.ErrorType}, error: {ce.ErrorMessage}"); + throw new AliyunSmsException(response.Body.Code, $"Text message sending failed, code:{response.Body.Code}, message:{response.Body.Message}!"); } } @@ -132,75 +114,58 @@ public class AliyunSmsSender : ISmsSender, IAliyunSmsVerifyCodeSender Check.NotNullOrWhiteSpace(signName, AliyunSettingNames.SmsVerifyCode.DefaultSignName); Check.NotNullOrWhiteSpace(templateCode, AliyunSettingNames.SmsVerifyCode.DefaultTemplateCode); - var request = new CommonRequest + var dypnsClient = await DypnsClientFactory.CreateAsync(); + + var request = new SendSmsVerifyCodeRequest { - Domain = domain, - Version = version, - Product = "Dypnsapi", - Method = MethodType.POST, - Action = "SendSmsVerifyCode", + PhoneNumber = message.PhoneNumber, + SignName = signName, + TemplateCode = templateCode, + TemplateParam = JsonSerializer.Serialize(message.TemplateParam), }; - request.AddBodyParameters("PhoneNumber", message.PhoneNumber); - request.AddBodyParameters("SignName", signName); - request.AddBodyParameters("TemplateCode", templateCode); - request.AddBodyParameters("TemplateParam", JsonSerializer.Serialize(message.TemplateParam)); - try + var response = await dypnsClient.SendSmsVerifyCodeAsync(request); + if (response.Body.Success == false) { - var client = await AcsClientFactory.CreateAsync(); - var response = client.GetCommonResponse(request); - var responseContent = Encoding.Default.GetString(response.HttpResponse.Content); - var aliyunResponse = JsonSerializer.Deserialize(responseContent); - if (!aliyunResponse.Success) + if (await SettingProvider.IsTrueAsync(AliyunSettingNames.Sms.VisableErrorToClient)) { - if (await SettingProvider.IsTrueAsync(AliyunSettingNames.Sms.VisableErrorToClient)) - { - throw new UserFriendlyException(aliyunResponse.Code, aliyunResponse.Message); - } - throw new AliyunSmsException(aliyunResponse.Code, $"Text message sending failed, code:{aliyunResponse.Code}, message:{aliyunResponse.Message}!"); + throw new UserFriendlyException(response.Body.Code, response.Body.Message); } - } - catch (ServerException se) - { - throw new AliyunSmsException(se.ErrorCode, $"Sending text messages to aliyun server is abnormal,type: {se.ErrorType}, error: {se.ErrorMessage}"); - } - catch (ClientException ce) - { - throw new AliyunSmsException(ce.ErrorCode, $"A client exception occurred in sending SMS messages,type: {ce.ErrorType}, error: {ce.ErrorMessage}"); + throw new AliyunSmsException(response.Body.Code, $"Text message sending failed, code:{response.Body.Code}, message:{response.Body.Message}!"); } } - private async Task TryAddTemplateCodeAsync(CommonRequest request, SmsMessage smsMessage) + private async Task TryAddTemplateCodeAsync(SendSmsRequest request, SmsMessage smsMessage) { - if (smsMessage.Properties.TryGetValue("TemplateCode", out object template) && template != null) + if (smsMessage.Properties.TryGetValue("TemplateCode", out var template) && template != null) { - request.AddQueryParameters("TemplateCode", template.ToString()); + request.TemplateCode = template.ToString(); smsMessage.Properties.Remove("TemplateCode"); } else { var defaultTemplateCode = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Sms.DefaultTemplateCode); Check.NotNullOrWhiteSpace(defaultTemplateCode, "TemplateCode"); - request.AddQueryParameters("TemplateCode", defaultTemplateCode); + request.TemplateCode = defaultTemplateCode; } } - private async Task TryAddSignNameAsync(CommonRequest request, SmsMessage smsMessage) + private async Task TryAddSignNameAsync(SendSmsRequest request, SmsMessage smsMessage) { - if (smsMessage.Properties.TryGetValue("SignName", out object signName) && signName != null) + if (smsMessage.Properties.TryGetValue("SignName", out var signName) && signName != null) { - request.AddQueryParameters("SignName", signName.ToString()); + request.SignName = signName.ToString(); smsMessage.Properties.Remove("SignName"); } else { var defaultSignName = await SettingProvider.GetOrNullAsync(AliyunSettingNames.Sms.DefaultSignName); Check.NotNullOrWhiteSpace(defaultSignName, "SignName"); - request.AddQueryParameters("SignName", defaultSignName); + request.SignName = defaultSignName; } } - private async Task TryAddSendPhoneAsync(CommonRequest request, SmsMessage smsMessage) + private async Task TryAddSendPhoneAsync(SendSmsRequest request, SmsMessage smsMessage) { if (smsMessage.PhoneNumber.IsNullOrWhiteSpace()) { @@ -210,20 +175,20 @@ public class AliyunSmsSender : ISmsSender, IAliyunSmsVerifyCodeSender defaultPhoneNumber, AliyunSettingNames.Sms.DefaultPhoneNumber, maxLength: 11, minLength: 11); - request.AddQueryParameters("PhoneNumbers", defaultPhoneNumber); + request.PhoneNumbers = defaultPhoneNumber; } else { - request.AddQueryParameters("PhoneNumbers", smsMessage.PhoneNumber); + request.PhoneNumbers = smsMessage.PhoneNumber; } } - private void TryAddTemplateParam(CommonRequest request, SmsMessage smsMessage) + private void TryAddTemplateParam(SendSmsRequest request, SmsMessage smsMessage) { if (smsMessage.Properties.Any()) { var queryParamJson = JsonSerializer.Serialize(smsMessage.Properties); - request.AddQueryParameters("TemplateParam", queryParamJson); + request.TemplateParam = queryParamJson; } } } diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DypnsClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DypnsClientFactory.cs new file mode 100644 index 000000000..3009b0f4e --- /dev/null +++ b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DypnsClientFactory.cs @@ -0,0 +1,41 @@ +using AlibabaCloud.SDK.Dypnsapi20170525; +using LINGYUN.Abp.Aliyun; +using System; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Settings; + +namespace LINGYUN.Abp.Sms.Aliyun; + +public class DypnsClientFactory : AliyunClientFactory, IDypnsClientFactory, ITransientDependency +{ + public DypnsClientFactory( + ISettingProvider settingProvider, + IDistributedCache cache) + : base(settingProvider, cache) + { + } + + protected override Client GetClient(string regionId, string accessKeyId, string accessKeySecret) + { + return new Client( + new AlibabaCloud.OpenApiClient.Models.Config + { + RegionId = regionId, + AccessKeyId = accessKeyId, + AccessKeySecret = accessKeySecret, + }); + } + + protected override Client GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken, DateTime? expiration = null) + { + return new Client( + new AlibabaCloud.OpenApiClient.Models.Config + { + RegionId = regionId, + AccessKeyId = accessKeyId, + AccessKeySecret = accessKeySecret, + SecurityToken = securityToken, + }); + } +} diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DysmsClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DysmsClientFactory.cs new file mode 100644 index 000000000..66aaff90e --- /dev/null +++ b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/DysmsClientFactory.cs @@ -0,0 +1,38 @@ +using AlibabaCloud.SDK.Dysmsapi20170525; +using LINGYUN.Abp.Aliyun; +using System; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Settings; + +namespace LINGYUN.Abp.Sms.Aliyun; + +public class DysmsClientFactory : AliyunClientFactory, IDysmsClientFactory, ITransientDependency +{ + public DysmsClientFactory(ISettingProvider settingProvider, IDistributedCache cache) : base(settingProvider, cache) + { + } + + protected override Client GetClient(string regionId, string accessKeyId, string accessKeySecret) + { + return new Client( + new AlibabaCloud.OpenApiClient.Models.Config + { + RegionId = regionId, + AccessKeyId = accessKeyId, + AccessKeySecret = accessKeySecret, + }); + } + + protected override Client GetSecurityTokenClient(string regionId, string accessKeyId, string accessKeySecret, string securityToken, DateTime? expiration = null) + { + return new Client( + new AlibabaCloud.OpenApiClient.Models.Config + { + RegionId = regionId, + AccessKeyId = accessKeyId, + AccessKeySecret = accessKeySecret, + SecurityToken = securityToken, + }); + } +} diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDypnsClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDypnsClientFactory.cs new file mode 100644 index 000000000..21364c171 --- /dev/null +++ b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDypnsClientFactory.cs @@ -0,0 +1,13 @@ +using AlibabaCloud.SDK.Dypnsapi20170525; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Sms.Aliyun; + +public interface IDypnsClientFactory +{ + /// + /// 构建短信认证客户端 + /// + /// + Task CreateAsync(); +} diff --git a/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDysmsClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDysmsClientFactory.cs new file mode 100644 index 000000000..b368f5066 --- /dev/null +++ b/aspnet-core/framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN/Abp/Sms/Aliyun/IDysmsClientFactory.cs @@ -0,0 +1,13 @@ +using AlibabaCloud.SDK.Dysmsapi20170525; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Sms.Aliyun; + +public interface IDysmsClientFactory +{ + /// + /// 构建短信客户端 + /// + /// + Task CreateAsync(); +} From 62aa3570518a96a35aebf864284096f8c03feecc Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 28 May 2026 09:41:32 +0800 Subject: [PATCH 16/40] feat: Optimize BlobManagement module --- Directory.Packages.props | 1 + .../Aliyun/AliyunBlobProvider.cs | 177 +++++++++++++----- ...ByKeyInput.cs => BlobDownloadByIdInput.cs} | 4 +- .../Dtos/BlobDownloadByNameInput.cs | 5 +- .../Abp/BlobManagement/IBlobAppService.cs | 8 +- .../BlobManagement/IPrivateBlobAppService.cs | 4 +- .../BlobManagement/IPublicBlobAppService.cs | 4 +- .../Integration/IBlobIntegrationService.cs | 2 +- .../Abp/BlobManagement/BlobAppService.cs | 25 ++- .../Abp/BlobManagement/BlobAppServiceBase.cs | 58 +++--- .../BlobWithoutContainerAppService.cs | 8 +- .../Integration/BlobIntegrationService.cs | 10 +- .../Abp/BlobManagement/BlobDownloadEto.cs | 8 +- .../LINGYUN/Abp/BlobManagement/Blob.cs | 42 +++-- .../Abp/BlobManagement/BlobDataSeeder.cs | 2 +- .../BlobManagement/BlobDownloadIncreaser.cs | 2 +- .../BlobDownloadKeyCacheItem.cs | 5 - .../LINGYUN/Abp/BlobManagement/BlobManager.cs | 31 +-- .../BlobManagement/BlobTempCleanupService.cs | 2 +- .../IBlobContainerRepository.cs | 1 + .../IBlobContainerRepositoryExtenssions.cs | 3 +- .../Abp/BlobManagement/IBlobProvider.cs | 4 +- .../EfCoreBlobContainerRepository.cs | 3 +- .../FileSystem/FileSystemBlobProvider.cs | 3 +- .../Abp/BlobManagement/BlobController.cs | 41 ++-- .../Integration/BlobIntegrationController.cs | 4 +- .../BlobManagement/PrivateBlobController.cs | 12 +- .../BlobManagement/PublicBlobController.cs | 12 +- .../BlobManagement/Minio/MinioBlobProvider.cs | 24 ++- .../Tencent/TencentBlobProvider.cs | 16 +- ...LY.MicroService.Applications.Single.csproj | 1 + 31 files changed, 343 insertions(+), 179 deletions(-) rename aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/{BlobDownloadByKeyInput.cs => BlobDownloadByIdInput.cs} (69%) diff --git a/Directory.Packages.props b/Directory.Packages.props index 7ef269c33..7c7d36b3d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -354,6 +354,7 @@ + diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs index 912320b7a..fa6af872e 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs @@ -1,4 +1,5 @@ -using Aliyun.OSS; +using AlibabaCloud.OSS.V2; +using AlibabaCloud.OSS.V2.Models; using LINGYUN.Abp.BlobStoring.Aliyun; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -50,23 +51,29 @@ public class AliyunBlobProvider : IBlobProvider { var client = await CreateClientAsync(); var bucket = NormalizeContainerName(name); + var configuration = GetBlobConfiguration(); - CreateBucketIfNotExists(client, bucket); + await CreateBucketIfNotExists(client, bucket, configuration.CreateBucketAcl, cancellationToken); } public async virtual Task DeleteContainerAsync( string name, CancellationToken cancellationToken = default) { - var client = await CreateClientAsync(); + var ossClient = await CreateClientAsync(); var bucket = NormalizeContainerName(name); - if (!BucketExists(client, bucket)) + if (!await BucketExists(ossClient, bucket, cancellationToken)) { return; } - client.DeleteBucket(bucket); + await ossClient.DeleteBucketAsync( + new DeleteBucketRequest + { + Bucket = bucket, + }, + cancellationToken: cancellationToken); } public async virtual Task DeleteBlobAsync( @@ -74,13 +81,19 @@ public class AliyunBlobProvider : IBlobProvider string blobName, CancellationToken cancellationToken = default) { - var client = await CreateClientAsync(); + var ossClient = await CreateClientAsync(); var bucket = NormalizeContainerName(containerName); var objectName = CalculateBlobName(blobName); - if (ObjectExists(client, bucket, objectName)) + if (await ObjectExists(ossClient, bucket, objectName, cancellationToken)) { - client.DeleteObject(bucket, objectName); + await ossClient.DeleteObjectAsync( + new DeleteObjectRequest + { + Bucket = bucket, + Key = objectName, + }, + cancellationToken: cancellationToken); } } @@ -98,39 +111,75 @@ public class AliyunBlobProvider : IBlobProvider string blobName, CancellationToken cancellationToken = default) { - var configuration = GetBlobConfiguration(); + var ossClient = await CreateClientAsync(); + var bucket = NormalizeContainerName(containerName); + var objectName = CalculateBlobName(blobName); - var downloadUrl = await GenerateDownloadUrlAsync( - containerName, - blobName, - TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), - cancellationToken); - if (downloadUrl.IsNullOrWhiteSpace()) + if (!await ObjectExists(ossClient, bucket, objectName, cancellationToken)) { return null; } - var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + var result = await ossClient.GetObjectAsync( + new GetObjectRequest + { + Bucket = bucket, + Key = blobName, + }); + + return result.Body; - return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + // TODO: 阿里云sdk预签名不可用[2026/05/23] + //var configuration = GetBlobConfiguration(); + + //var downloadUrl = await GeneratePresignedUrlAsync( + // containerName, + // blobName, + // TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), + // cancellationToken: cancellationToken); + //if (downloadUrl.IsNullOrWhiteSpace()) + //{ + // return null; + //} + + //var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + + //return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); } - public async virtual Task GenerateDownloadUrlAsync( + public virtual Task GeneratePresignedUrlAsync( string containerName, string blobName, TimeSpan expiration, + bool isAttachmentContent = true, CancellationToken cancellationToken = default) { - var client = await CreateClientAsync(); - var bucket = NormalizeContainerName(containerName); - var objectName = CalculateBlobName(blobName); - - if (!ObjectExists(client, bucket, objectName)) - { - return null; - } - - return client.GeneratePresignedUri(bucket, objectName, Clock.Now.Add(expiration)).ToString(); + // TODO: 阿里云sdk预签名不可用[2026/05/23] + return Task.FromResult(null); + //var ossClient = await CreateClientAsync(); + //var bucket = NormalizeContainerName(containerName); + //var objectName = CalculateBlobName(blobName); + + //if (!await ObjectExists(ossClient, bucket, objectName, cancellationToken)) + //{ + // return null; + //} + + //var fileName = Path.GetFileName(blobName); + //var type = isAttachmentContent ? "attachment" : "inline"; + //var disposition = $"{type}; filename=\"{Uri.EscapeDataString(fileName)}\"; " + + // $"filename*=UTF-8''{Uri.EscapeDataString(fileName)}"; + + //var presignResult = ossClient.Presign( + // new GetObjectRequest + // { + // Bucket = bucket, + // Key = blobName, + // ResponseContentDisposition = disposition, + // }, + // Clock.Now.Add(expiration)); + + //return presignResult.Url; } public virtual Task CreateFolderAsync( @@ -150,49 +199,79 @@ public class AliyunBlobProvider : IBlobProvider string? contentType = null, CancellationToken cancellationToken = default) { - var client = await CreateClientAsync(); + var ossClient = await CreateClientAsync(); var bucket = NormalizeContainerName(containerName); var objectName = CalculateBlobName(blobName); + var configuration = GetBlobConfiguration(); - CreateBucketIfNotExists(client, bucket); - - var objectMetadata = new ObjectMetadata(); - if (!contentType.IsNullOrWhiteSpace()) - { - objectMetadata.ContentType = contentType; - } - - client.PutObject(bucket, objectName, content, objectMetadata); + await CreateBucketIfNotExists(ossClient, bucket, configuration.CreateBucketAcl, cancellationToken); + + await ossClient.PutObjectAsync( + new PutObjectRequest + { + Bucket = bucket, + Key = objectName, + Body = content, + ContentType = contentType, + }, + cancellationToken: cancellationToken); } protected virtual AliyunBlobProviderConfiguration GetBlobConfiguration() { var configuration = ConfigurationProvider.Get(); - var blobConfiguration = configuration.GetAliyunConfiguration(); - return blobConfiguration; + return configuration.GetAliyunConfiguration(); } - protected async virtual Task CreateClientAsync() + protected async virtual Task CreateClientAsync() { - return await OssClientFactory.CreateAsync(); + var configuration = GetBlobConfiguration(); + return await OssClientFactory.CreateAsync(configuration); } - protected virtual void CreateBucketIfNotExists(IOss oss, string bucket) + protected async virtual Task CreateBucketIfNotExists( + Client ossClient, + string bucket, + BucketAclType? bucketAcl = null, + CancellationToken cancellationToken = default) { - if (!BucketExists(oss, bucket)) + if (!await BucketExists(ossClient, bucket, cancellationToken)) { - oss.CreateBucket(bucket); + await ossClient.PutBucketAsync( + new PutBucketRequest + { + Bucket = bucket, + }, + cancellationToken: cancellationToken); + + if (bucketAcl.HasValue) + { + await ossClient.PutBucketAclAsync( + new PutBucketAclRequest + { + Bucket = bucket, + Acl = bucketAcl.Value.GetString(), + }, + cancellationToken: cancellationToken); + } } } - protected virtual bool BucketExists(IOss oss, string bucket) + protected async virtual Task BucketExists( + Client ossClient, + string bucket, + CancellationToken cancellationToken = default) { - return oss.DoesBucketExist(bucket); + return await ossClient.IsBucketExistAsync(bucket, cancellationToken); } - protected virtual bool ObjectExists(IOss oss, string bucket, string objectName) + protected async virtual Task ObjectExists( + Client ossClient, + string bucket, + string objectName, + CancellationToken cancellationToken = default) { - return oss.DoesObjectExist(bucket, objectName); + return await ossClient.IsObjectExistAsync(bucket, objectName, cancellationToken: cancellationToken); } protected virtual string GetPrefixPath() diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByIdInput.cs similarity index 69% rename from aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs rename to aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByIdInput.cs index fb5da0020..4ac8d1f43 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByKeyInput.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByIdInput.cs @@ -3,10 +3,10 @@ using System.ComponentModel.DataAnnotations; namespace LINGYUN.Abp.BlobManagement.Dtos; -public class BlobDownloadByKeyInput +public class BlobDownloadByIdInput { public Guid? TenantId { get; set; } [Required] - public string Key { get; set; } + public Guid Id { get; set; } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByNameInput.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByNameInput.cs index 77715bb07..06663bc67 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByNameInput.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Dtos/BlobDownloadByNameInput.cs @@ -1,10 +1,13 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; using Volo.Abp.Validation; namespace LINGYUN.Abp.BlobManagement.Dtos; public class BlobDownloadByNameInput { + public Guid? TenantId { get; set; } + [Required] [DynamicStringLength(typeof(BlobContainerConsts), nameof(BlobContainerConsts.MaxNameLength))] public string ContainerName { get; set; } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs index 2d4679569..4ed63da58 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IBlobAppService.cs @@ -17,13 +17,15 @@ public interface IBlobAppService : IApplicationService Task DeleteAsync(Guid id); + Task GeneratePreviewUrlAsync(Guid id); + Task GenerateDownloadUrlAsync(Guid id); - Task DownloadAsync(BlobDownloadByKeyInput input); + Task DownloadAsync(BlobDownloadByIdInput input); - Task GetContentAsync(Guid id); + Task PreviewAsync(BlobDownloadByIdInput input); - Task GetContentByNameAsync(BlobDownloadByNameInput input); + Task DownloadByNameAsync(BlobDownloadByNameInput input); Task GetAsync(Guid id); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPrivateBlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPrivateBlobAppService.cs index 9d25f2704..7164d938a 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPrivateBlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPrivateBlobAppService.cs @@ -17,9 +17,9 @@ public interface IPrivateBlobAppService : IApplicationService Task DeleteAsync(Guid id); - Task GetContentAsync(Guid id); + Task DownloadAsync(Guid id); - Task GetContentByNameAsync(string name); + Task DownloadByNameAsync(string name); Task GetAsync(Guid id); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPublicBlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPublicBlobAppService.cs index dff540187..c381482c4 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPublicBlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/IPublicBlobAppService.cs @@ -9,9 +9,9 @@ namespace LINGYUN.Abp.BlobManagement; public interface IPublicBlobAppService : IApplicationService { - Task GetContentAsync(Guid id); + Task DownloadAsync(Guid id); - Task GetContentByNameAsync(string name); + Task DownloadByNameAsync(string name); Task GetAsync(Guid id); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Integration/IBlobIntegrationService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Integration/IBlobIntegrationService.cs index 40a1fa835..ce105fec2 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Integration/IBlobIntegrationService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application.Contracts/LINGYUN/Abp/BlobManagement/Integration/IBlobIntegrationService.cs @@ -16,5 +16,5 @@ public interface IBlobIntegrationService : IApplicationService Task ExistsAsync(BlobFileGetByNameIntegrationDto input); - Task GetContentAsync(BlobFileGetByNameIntegrationDto input); + Task DownloadAsync(BlobFileGetByNameIntegrationDto input); } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs index 689395ef4..ecafc86c1 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppService.cs @@ -47,11 +47,30 @@ public class BlobAppService : BlobAppServiceBase, IBlobAppService return await base.CreateFolderAsync(blobContainer, input); } - public async virtual Task GetContentByNameAsync(BlobDownloadByNameInput input) + public async virtual Task DownloadAsync(BlobDownloadByIdInput input) { - var blobContainer = await BlobContainerRepository.GetByNameAsync(input.ContainerName); + using (CurrentTenant.Change(input.TenantId ?? CurrentTenant.Id)) + { + return await base.DownloadAsync(input.Id); + } + } + + public async virtual Task PreviewAsync(BlobDownloadByIdInput input) + { + using (CurrentTenant.Change(input.TenantId ?? CurrentTenant.Id)) + { + return await base.DownloadAsync(input.Id); + } + } + + public async virtual Task DownloadByNameAsync(BlobDownloadByNameInput input) + { + using (CurrentTenant.Change(input.TenantId ?? CurrentTenant.Id)) + { + var blobContainer = await BlobContainerRepository.GetByNameAsync(BlobManager.GetBlobProvider(), input.ContainerName); - return await base.GetContentByNameAsync(blobContainer, input.BlobName); + return await base.DownloadByNameAsync(blobContainer, input.BlobName); + } } protected async override Task CheckGetPolicyAsync(string containerName, Blob blob) diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs index 683e6b1ce..638234cf8 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs @@ -48,43 +48,15 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService public async virtual Task GenerateDownloadUrlAsync(Guid id) { - var blob = await BlobRepository.GetAsync(id); - var blobContainer = await BlobContainerRepository.GetAsync(blob.ContainerId); - - await CheckGetPolicyAsync(blob); - - var fallbackUrlPrefix = blob.TenantId.HasValue - ? $"/api/{BlobManagementRemoteServiceConsts.ModuleName}/blobs/download/t/{blob.TenantId:N}" - : $"/api/{BlobManagementRemoteServiceConsts.ModuleName}/blobs/download"; - - var downloadUrl = await BlobManager.GenerateDownloadUrlAsync( - blobContainer, - blob, - fallbackUrlPrefix); - - return downloadUrl; + return await GenerateDownloadUrlAsync(id, "download"); } - public async virtual Task DownloadAsync(BlobDownloadByKeyInput input) + public async virtual Task GeneratePreviewUrlAsync(Guid id) { - using (CurrentTenant.Change(input.TenantId)) - { - var blob = await BlobManager.FindBlobByDownloadKeyAsync(input.Key); - if (blob == null) - { - return new RemoteStreamContent(Stream.Null, input.Key); - } - - // 临时下载链接一般用于临时预览与下载, 过期时间短, 不校验权限 - // await CheckGetPolicyAsync(blob); - - var stream = await BlobManager.DownloadBlobsync(blob); - - return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); - } + return await GenerateDownloadUrlAsync(id, "preview", isAttachmentContent: false); } - public async virtual Task GetContentAsync(Guid id) + public async virtual Task DownloadAsync(Guid id) { var blob = await BlobRepository.GetAsync(id); @@ -185,7 +157,7 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService return ObjectMapper.Map(blob); } - protected async virtual Task GetContentByNameAsync(BlobContainer blobContainer, string name) + protected async virtual Task DownloadByNameAsync(BlobContainer blobContainer, string name) { var blob = await FindBlobByNameAsync(blobContainer, name) ?? throw new BusinessException( @@ -200,6 +172,26 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); } + protected async virtual Task GenerateDownloadUrlAsync(Guid id, string method, bool isAttachmentContent = true) + { + var blob = await BlobRepository.GetAsync(id); + var blobContainer = await BlobContainerRepository.GetAsync(blob.ContainerId); + + await CheckGetPolicyAsync(blob); + + var fallbackDownloadUrl = blob.TenantId.HasValue + ? $"/api/{BlobManagementRemoteServiceConsts.ModuleName}/blobs/{method}/t/{blob.TenantId:N}/{blob.Id:N}" + : $"/api/{BlobManagementRemoteServiceConsts.ModuleName}/blobs/{method}/{blob.Id:N}"; + + var downloadUrl = await BlobManager.GenerateDownloadUrlAsync( + blobContainer, + blob, + fallbackDownloadUrl, + isAttachmentContent); + + return downloadUrl; + } + protected async virtual Task FindBlobByNameAsync(BlobContainer blobContainer, string name) { var blobName = HttpUtility.UrlDecode(name); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs index 66ed740d8..b4de50123 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobWithoutContainerAppService.cs @@ -42,11 +42,11 @@ public abstract class BlobWithoutContainerAppService : BlobAppServiceBase return await base.CreateFolderAsync(blobContainer, input); } - public async virtual Task GetContentByNameAsync(string name) + public async virtual Task DownloadByNameAsync(string name) { - var blobContainer = await BlobContainerRepository.GetByNameAsync(ContainerName); + var blobContainer = await BlobContainerRepository.GetByNameAsync(BlobManager.GetBlobProvider(), ContainerName); - return await base.GetContentByNameAsync(blobContainer, name); + return await base.DownloadByNameAsync(blobContainer, name); } public async virtual Task> GetListAsync(BlobGetPagedListWithoutContainerInput input) @@ -67,7 +67,7 @@ public abstract class BlobWithoutContainerAppService : BlobAppServiceBase protected async virtual Task GetOrCreateContainer() { - var blobContainer = await BlobContainerRepository.FindByNameAsync(ContainerName) + var blobContainer = await BlobManager.FindContainerAsync(ContainerName) ?? await BlobManager.CreateContainerAsync(ContainerName); return blobContainer; diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs index 367da5ba9..b1c1cf24a 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationService.cs @@ -28,7 +28,7 @@ public class BlobIntegrationService : BlobAppServiceBase, IBlobIntegrationServic public async virtual Task CreateAsync(BlobFileCreateIntegrationDto input) { - var blobContainer = await BlobContainerRepository.GetByNameAsync(input.ContainerName); + var blobContainer = await BlobContainerRepository.GetByNameAsync(BlobManager.GetBlobProvider(), input.ContainerName); // Example: /a/b/c/d/f.txt var blobName = HttpUtility.UrlDecode(input.BlobName); @@ -63,7 +63,7 @@ public class BlobIntegrationService : BlobAppServiceBase, IBlobIntegrationServic public async virtual Task DeleteAsync(BlobFileGetByNameIntegrationDto input) { - var blobContainer = await BlobContainerRepository.GetByNameAsync(input.ContainerName); + var blobContainer = await BlobContainerRepository.GetByNameAsync(BlobManager.GetBlobProvider(), input.ContainerName); var blob = await FindBlobByNameAsync(blobContainer, input.BlobName) ?? throw new BusinessException( @@ -90,12 +90,12 @@ public class BlobIntegrationService : BlobAppServiceBase, IBlobIntegrationServic } } - public async virtual Task GetContentAsync(BlobFileGetByNameIntegrationDto input) + public async virtual Task DownloadAsync(BlobFileGetByNameIntegrationDto input) { try { - var blobContainer = await BlobContainerRepository.GetByNameAsync(input.ContainerName); - return await GetContentByNameAsync(blobContainer, input.BlobName); + var blobContainer = await BlobContainerRepository.GetByNameAsync(BlobManager.GetBlobProvider(), input.ContainerName); + return await DownloadByNameAsync(blobContainer, input.BlobName); } catch (Exception ex) { diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobDownloadEto.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobDownloadEto.cs index 03d5d2d0a..f5fa5f2fb 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobDownloadEto.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/BlobDownloadEto.cs @@ -6,6 +6,7 @@ namespace LINGYUN.Abp.BlobManagement; public class BlobDownloadEto : IMultiTenant { public Guid? TenantId { get; set; } + public string Provider { get; set; } public string ContainerName { get; set; } public string FullName { get; set; } public BlobDownloadEto() @@ -13,8 +14,13 @@ public class BlobDownloadEto : IMultiTenant } - public BlobDownloadEto(string containerName, string fullName, Guid? tenantId = null) + public BlobDownloadEto( + string provider, + string containerName, + string fullName, + Guid? tenantId = null) { + Provider = provider; ContainerName = containerName; FullName = fullName; TenantId = tenantId; diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/Blob.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/Blob.cs index 51258d7be..162938e81 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/Blob.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/Blob.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Xml.Linq; using Volo.Abp; using Volo.Abp.Data; using Volo.Abp.Domain.Entities.Auditing; @@ -67,6 +68,14 @@ public class Blob : AuditedAggregateRoot, IMultiTenant this.SetDefaultsForExtraProperties(); } + public void MoveTo(Blob parentBlob) + { + ValidateSubBlob(parentBlob, Name); + ParentId = parentBlob.Id; + parentBlob.Blobs.Add(this); + parentBlob.CalculateSize(); + } + public void SetFullName(string fullName) { FullName = Check.NotNullOrWhiteSpace(fullName, nameof(fullName), BlobConsts.MaxFullNameLength); @@ -99,20 +108,7 @@ public class Blob : AuditedAggregateRoot, IMultiTenant BlobType type, long? size = null) { - if (Type != BlobType.Folder) - { - throw new BusinessException( - BlobManagementErrorCodes.Blob.NonFolderChildBlob, - "Sub-files/directories cannot be added to non-directory types!"); - } - - if (HasBlob(name)) - { - throw new BusinessException( - BlobManagementErrorCodes.Blob.NameAlreadyExists, - $"There is already a file/directory named {name} in the current directory!") - .WithData("Name", name); - } + ValidateSubBlob(this, name); var blob = new Blob( id, @@ -183,4 +179,22 @@ public class Blob : AuditedAggregateRoot, IMultiTenant return blobPath.EnsureEndsWith('/') + blobName.RemovePreFix("/"); } + + public static void ValidateSubBlob(Blob parentBlob, string subBlobName) + { + if (parentBlob.Type != BlobType.Folder) + { + throw new BusinessException( + BlobManagementErrorCodes.Blob.NonFolderChildBlob, + "Sub-files/directories cannot be added to non-directory types!"); + } + + if (parentBlob.HasBlob(subBlobName)) + { + throw new BusinessException( + BlobManagementErrorCodes.Blob.NameAlreadyExists, + $"There is already a file/directory named {subBlobName} in the current directory!") + .WithData("Name", subBlobName); + } + } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDataSeeder.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDataSeeder.cs index e83516959..703e0ac6c 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDataSeeder.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDataSeeder.cs @@ -41,7 +41,7 @@ public class BlobDataSeeder : IBlobDataSeeder, ITransientDependency { Logger.LogInformation("Seeding container {containerName}...", containerName); - if (await BlobContainerRepository.FindByNameAsync(containerName) == null) + if (await BlobManager.FindContainerAsync(containerName) == null) { await BlobManager.CreateContainerAsync(containerName); } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadIncreaser.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadIncreaser.cs index bcf2da457..ca074afce 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadIncreaser.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadIncreaser.cs @@ -37,7 +37,7 @@ public class BlobDownloadIncreaser : return; } - var blobContainer = await _blobContainerRepository.FindByNameAsync(eventData.ContainerName); + var blobContainer = await _blobContainerRepository.FindByNameAsync(eventData.Provider, eventData.ContainerName); if (blobContainer == null) { return; diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs index 7c001efa9..2f4914c91 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobDownloadKeyCacheItem.cs @@ -16,9 +16,4 @@ public class BlobDownloadKeyCacheItem BlobId = blobId; Url = url; } - - public static string CalculateCacheKey(Guid blobId, string blobName) - { - return $"{blobId:N}{blobName.RemovePreFix("/")}"; - } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs index 68df23011..bf2c0a00d 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobManager.cs @@ -62,11 +62,16 @@ public class BlobManager : DomainService _settingProvider = settingProvider; } - public async virtual Task CreateContainerAsync(string name) + public async virtual Task FindContainerAsync(string name) { Check.NotNullOrWhiteSpace(name, nameof(name)); - if (await _blobContainerRepository.FindByNameAsync(name) != null) + return await _blobContainerRepository.FindByNameAsync(GetBlobProvider(), name); + } + + public async virtual Task CreateContainerAsync(string name) + { + if (await FindContainerAsync(name) != null) { throw new BusinessException( BlobManagementErrorCodes.Container.NameAlreadyExists, @@ -81,7 +86,7 @@ public class BlobManager : DomainService await _blobProvider.CreateContainerAsync(blobContainer.Name, GetCancellationToken()); - blobContainer.SetProvider(_blobProvider.Name); + blobContainer.SetProvider(GetBlobProvider()); await _blobContainerRepository.InsertAsync(blobContainer); @@ -153,7 +158,7 @@ public class BlobManager : DomainService { await _blobProvider.CreateFolderAsync(blobContainer.Name, blob.FullName, GetCancellationToken()); - blob.SetProvider(_blobProvider.Name); + blob.SetProvider(GetBlobProvider()); } await _blobRepository.InsertAsync(blob); @@ -227,7 +232,7 @@ public class BlobManager : DomainService contentType, GetCancellationToken()); - blob.SetProvider(_blobProvider.Name); + blob.SetProvider(GetBlobProvider()); blob.SetFileInfo(contentType, stream.Length); return blob; @@ -292,7 +297,7 @@ public class BlobManager : DomainService } else { - blobContainer = await _blobContainerRepository.GetByNameAsync(containerIdOrName); + blobContainer = await _blobContainerRepository.GetByNameAsync(GetBlobProvider(), containerIdOrName); } if (parentId.HasValue) { @@ -338,9 +343,10 @@ public class BlobManager : DomainService public async virtual Task GenerateDownloadUrlAsync( BlobContainer blobContainer, Blob blob, - string fallbackUrlPrefix) + string fallbackDownloadUrl, + bool isAttachmentContent = true) { - var cacheKey = BlobDownloadKeyCacheItem.CalculateCacheKey(blob.Id, blob.FullName); + var cacheKey = $"{fallbackDownloadUrl.ToMd5()}"; var cacheItem = await _blobDownloadKeyCache.GetAsync(cacheKey); if (cacheItem == null) { @@ -348,16 +354,17 @@ public class BlobManager : DomainService BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds, BlobManagementSettingNames.DefaultGenerateDownloadUrlExpirySeconds); - var downloadUrl = await _blobProvider.GenerateDownloadUrlAsync( + var downloadUrl = await _blobProvider.GeneratePresignedUrlAsync( blobContainer.Name, blob.FullName, TimeSpan.FromSeconds(downloadUrlExpirySeconds), + isAttachmentContent, GetCancellationToken()); if (downloadUrl.IsNullOrWhiteSpace()) { - // 特殊对象存储提供者(FileSystem)无法生成下载链接, 回退指定的请求Url前缀 - downloadUrl = fallbackUrlPrefix.EnsureEndsWith('/') + cacheKey; + // 特殊对象存储提供者(FileSystem)无法生成下载链接, 回退指定的请求Url + downloadUrl = fallbackDownloadUrl; } cacheItem = new BlobDownloadKeyCacheItem( @@ -403,7 +410,7 @@ public class BlobManager : DomainService downloadCacheItem.DownloadCount += 1; await _blobDownloadCache.SetAsync(downloadCacheKey, downloadCacheItem); - await _distributedEventBus.PublishAsync(new BlobDownloadEto(containerName, blobName, CurrentTenant.Id)); + await _distributedEventBus.PublishAsync(new BlobDownloadEto(GetBlobProvider(), containerName, blobName, CurrentTenant.Id)); } return blobStream; diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobTempCleanupService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobTempCleanupService.cs index c34de069f..8daa9c837 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobTempCleanupService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/BlobTempCleanupService.cs @@ -50,7 +50,7 @@ public class BlobTempCleanupService : ITransientDependency try { - var tempBlobContainer = await BlobContainerRepository.FindByNameAsync("temp"); + var tempBlobContainer = await BlobManager.FindContainerAsync("temp"); if (tempBlobContainer == null) { Logger.LogInformation($"No temp container found."); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepository.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepository.cs index f80d6d228..1dc197e48 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepository.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepository.cs @@ -14,6 +14,7 @@ public interface IBlobContainerRepository : IBasicRepository FindByNameAsync( + string provider, string name, CancellationToken cancellationToken = default); diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepositoryExtenssions.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepositoryExtenssions.cs index b5795e01f..e967db5e0 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepositoryExtenssions.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobContainerRepositoryExtenssions.cs @@ -8,10 +8,11 @@ public static class IBlobContainerRepositoryExtenssions { public async static Task GetByNameAsync( this IBlobContainerRepository repository, + string provider, string name, CancellationToken cancellationToken = default) { - return await repository.FindByNameAsync(name, cancellationToken) + return await repository.FindByNameAsync(provider, name, cancellationToken) ?? throw new BusinessException( BlobManagementErrorCodes.Container.NameNotFound, $"There is no blob container named {name}!") diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs index 01a012279..61066f83b 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain/LINGYUN/Abp/BlobManagement/IBlobProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -22,10 +23,11 @@ public interface IBlobProvider string blobName, CancellationToken cancellationToken = default); - Task GenerateDownloadUrlAsync( + Task GeneratePresignedUrlAsync( string containerName, string blobName, TimeSpan expiration, + bool isAttachmentContent = true, CancellationToken cancellationToken = default); Task CreateFolderAsync( diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.EntityFrameworkCore/LINGYUN/Abp/BlobManagement/EntityFrameworkCore/EfCoreBlobContainerRepository.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.EntityFrameworkCore/LINGYUN/Abp/BlobManagement/EntityFrameworkCore/EfCoreBlobContainerRepository.cs index 145b304fe..aca9be141 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.EntityFrameworkCore/LINGYUN/Abp/BlobManagement/EntityFrameworkCore/EfCoreBlobContainerRepository.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.EntityFrameworkCore/LINGYUN/Abp/BlobManagement/EntityFrameworkCore/EfCoreBlobContainerRepository.cs @@ -30,11 +30,12 @@ public class EfCoreBlobContainerRepository : EfCoreRepository FindByNameAsync( + string provider, string name, CancellationToken cancellationToken = default) { return await (await GetQueryableAsync()) - .Where(x => x.Name == name) + .Where(x => x.Provider == provider && x.Name == name) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs index 8fcbc8b0f..097e4138b 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN/Abp/BlobManagement/FileSystem/FileSystemBlobProvider.cs @@ -99,10 +99,11 @@ public class FileSystemBlobProvider : IBlobProvider return Task.FromResult(File.OpenRead(fileName)); } - public virtual Task GenerateDownloadUrlAsync( + public virtual Task GeneratePresignedUrlAsync( string containerName, string blobName, TimeSpan expiration, + bool isAttachmentContent = true, CancellationToken cancellationToken = default) { // 本地文件系统无需生成下载链接 diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs index 696f7d391..4cff719d0 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/BlobController.cs @@ -1,5 +1,6 @@ using LINGYUN.Abp.BlobManagement.Dtos; using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; using System; using System.Threading.Tasks; using Volo.Abp; @@ -50,16 +51,34 @@ public class BlobController : BlobControllerBase, IBlobAppService return _service.DeleteAsync(id); } - [HttpGet("uid/{id}/content")] - public virtual Task GetContentAsync(Guid id) + [HttpGet("download/{id}")] + [HttpGet("download/t/{tenantId}/{id}")] + public virtual Task DownloadAsync(BlobDownloadByIdInput input) { - return _service.GetContentAsync(id); + return _service.DownloadAsync(input); + } + + [HttpGet("preview/{id}")] + [HttpGet("preview/t/{tenantId}/{id}")] + public async virtual Task PreviewAsync(BlobDownloadByIdInput input) + { + var content = await _service.PreviewAsync(input); + + if (!content.FileName.IsNullOrWhiteSpace()) + { + var contentDisposition = new ContentDispositionHeaderValue("inline"); + contentDisposition.SetHttpFileName(content.FileName); + HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString(); + } + + return content; } - [HttpGet("content")] - public virtual Task GetContentByNameAsync(BlobDownloadByNameInput input) + [HttpGet("download/by-name/{name}")] + [HttpGet("download/by-name/t/{tenantId}/{name}")] + public virtual Task DownloadByNameAsync(BlobDownloadByNameInput input) { - return _service.GetContentByNameAsync(input); + return _service.DownloadByNameAsync(input); } [HttpGet("{id}")] @@ -74,17 +93,15 @@ public class BlobController : BlobControllerBase, IBlobAppService return _service.GetListAsync(input); } - [HttpGet("{id}/generate-url")] + [HttpGet("generate/download-url/{id}")] public virtual Task GenerateDownloadUrlAsync(Guid id) { return _service.GenerateDownloadUrlAsync(id); } - [HttpGet] - [Route("download/{Key}")] - [Route("download/t/{TenantId}/{Key}")] - public virtual Task DownloadAsync(BlobDownloadByKeyInput input) + [HttpGet("generate/preview-url/{id}")] + public virtual Task GeneratePreviewUrlAsync(Guid id) { - return _service.DownloadAsync(input); + return _service.GeneratePreviewUrlAsync(id); } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationController.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationController.cs index dac00f68f..dc6b4efa0 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationController.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/Integration/BlobIntegrationController.cs @@ -40,8 +40,8 @@ public class BlobIntegrationController : AbpControllerBase, IBlobIntegrationServ } [HttpGet("download")] - public virtual Task GetContentAsync(BlobFileGetByNameIntegrationDto input) + public virtual Task DownloadAsync(BlobFileGetByNameIntegrationDto input) { - return _service.GetContentAsync(input); + return _service.DownloadAsync(input); } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PrivateBlobController.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PrivateBlobController.cs index f8ec336a7..20a3b4c1d 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PrivateBlobController.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PrivateBlobController.cs @@ -50,16 +50,16 @@ public class PrivateBlobController : BlobControllerBase, IPrivateBlobAppService return _service.DeleteAsync(id); } - [HttpGet("uid/{id}/content")] - public virtual Task GetContentAsync(Guid id) + [HttpGet("download/{id}")] + public virtual Task DownloadAsync(Guid id) { - return _service.GetContentAsync(id); + return _service.DownloadAsync(id); } - [HttpGet("content/{name}")] - public virtual Task GetContentByNameAsync(string name) + [HttpGet("download/by-name/{name}")] + public virtual Task DownloadByNameAsync(string name) { - return _service.GetContentByNameAsync(name); + return _service.DownloadByNameAsync(name); } [HttpGet("{id}")] diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PublicBlobController.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PublicBlobController.cs index aca0a128f..ab4610536 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PublicBlobController.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN/Abp/BlobManagement/PublicBlobController.cs @@ -22,16 +22,16 @@ public class PublicBlobController : BlobControllerBase, IPublicBlobAppService _service = service; } - [HttpGet("uid/{id}/content")] - public virtual Task GetContentAsync(Guid id) + [HttpGet("download/{id}")] + public virtual Task DownloadAsync(Guid id) { - return _service.GetContentAsync(id); + return _service.DownloadAsync(id); } - [HttpGet("content/{name}")] - public virtual Task GetContentByNameAsync(string name) + [HttpGet("download/by-name/{name}")] + public virtual Task DownloadByNameAsync(string name) { - return _service.GetContentByNameAsync(name); + return _service.DownloadByNameAsync(name); } [HttpGet("{id}")] diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs index 69414c0c9..a3922136a 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN/Abp/BlobManagement/Minio/MinioBlobProvider.cs @@ -4,6 +4,7 @@ using Minio; using Minio.DataModel.Args; using Minio.Exceptions; using System; +using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading; @@ -108,11 +109,11 @@ public class MinioBlobProvider : IBlobProvider { var configuration = GetBlobConfiguration(); - var downloadUrl = await GenerateDownloadUrlAsync( + var downloadUrl = await GeneratePresignedUrlAsync( containerName, blobName, TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), - cancellationToken); + cancellationToken: cancellationToken); if (downloadUrl.IsNullOrWhiteSpace()) { return null; @@ -123,10 +124,11 @@ public class MinioBlobProvider : IBlobProvider return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); } - public async virtual Task GenerateDownloadUrlAsync( + public async virtual Task GeneratePresignedUrlAsync( string containerName, string blobName, TimeSpan expiration, + bool isAttachmentContent = true, CancellationToken cancellationToken = default) { var client = GetMinioClient(); @@ -138,11 +140,21 @@ public class MinioBlobProvider : IBlobProvider return null; } - return await client.PresignedGetObjectAsync( - new PresignedGetObjectArgs() + var presignedGetObjectArgs = new PresignedGetObjectArgs() .WithBucket(bucket) .WithObject(objectName) - .WithExpiry(expiration.TotalSeconds.To())); + .WithExpiry(expiration.TotalSeconds.To()); + + var fileName = Path.GetFileName(blobName); + var type = isAttachmentContent ? "attachment" : "inline"; + var disposition = $"{type}; filename=\"{Uri.EscapeDataString(fileName)}\"; " + + $"filename*=UTF-8''{Uri.EscapeDataString(fileName)}"; + presignedGetObjectArgs.WithHeaders(new Dictionary() + { + { "response-content-disposition", disposition }, + }); + + return await client.PresignedGetObjectAsync(presignedGetObjectArgs); } public virtual Task CreateFolderAsync( diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs index 671525b8d..acdac8f47 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs @@ -6,6 +6,7 @@ using LINGYUN.Abp.BlobStoring.Tencent; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; +using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading; @@ -103,11 +104,11 @@ public class TencentBlobProvider : IBlobProvider { var configuration = await GetBlobConfiguration(); - var downloadUrl = await GenerateDownloadUrlAsync( + var downloadUrl = await GeneratePresignedUrlAsync( containerName, blobName, TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), - cancellationToken); + cancellationToken: cancellationToken); if (downloadUrl.IsNullOrWhiteSpace()) { return null; @@ -118,10 +119,11 @@ public class TencentBlobProvider : IBlobProvider return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); } - public async virtual Task GenerateDownloadUrlAsync( + public async virtual Task GeneratePresignedUrlAsync( string containerName, string blobName, TimeSpan expiration, + bool isAttachmentContent = true, CancellationToken cancellationToken = default) { var client = await CreateClientAsync(); @@ -147,6 +149,14 @@ public class TencentBlobProvider : IBlobProvider headers = null, //签名中需要校验的 header queryParameters = null //签名中需要校验的 URL 中请求参数 }; + var fileName = Path.GetFileName(blobName); + var type = isAttachmentContent ? "attachment" : "inline"; + var disposition = $"{type}; filename=\"{Uri.EscapeDataString(fileName)}\"; " + + $"filename*=UTF-8''{Uri.EscapeDataString(fileName)}"; + preSignatureStruct.queryParameters = new Dictionary + { + { "response-content-disposition", disposition }, + }; return client.GenerateSignURL(preSignatureStruct); } diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index e04cb7fee..e238f4cc1 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -6,6 +6,7 @@ net10.0 enable LY.MicroService.Applications.Single + A47DB958-CC3F-430B-A18A-57AA535BAB49 enable 10.2.0 From 215c9364ded64114f9ea83713556b313ca2d1a80 Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 28 May 2026 09:43:50 +0800 Subject: [PATCH 17/40] feat: Optimize the file preview - use `vue-files-preview` package --- apps/vben5/apps/app-antd/src/store/auth.ts | 1 + .../@abp/blob-management/package.json | 5 +- .../blob-management/src/api/useBlobsApi.ts | 26 ++++- .../components/blobs/BlobFilePreviewModal.vue | 4 +- .../blobs/BlobFilePreviewModal1.vue | 106 ++++++++++++++++++ .../src/components/blobs/BlobFileTable.vue | 9 +- apps/vben5/pnpm-workspace.yaml | 2 + 7 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal1.vue diff --git a/apps/vben5/apps/app-antd/src/store/auth.ts b/apps/vben5/apps/app-antd/src/store/auth.ts index 51e03bfcb..e93399281 100644 --- a/apps/vben5/apps/app-antd/src/store/auth.ts +++ b/apps/vben5/apps/app-antd/src/store/auth.ts @@ -180,6 +180,7 @@ export const useAuthStore = defineStore('auth', () => { userId: userInfoRes.sub ?? abpConfig.currentUser.id, username: userInfoRes.uniqueName ?? abpConfig.currentUser.userName, realName: + userInfoRes.given_name ?? userInfoRes.name ?? abpConfig.currentUser.name ?? abpConfig.currentUser.userName, diff --git a/apps/vben5/packages/@abp/blob-management/package.json b/apps/vben5/packages/@abp/blob-management/package.json index de1e2f0ec..93fddb80b 100644 --- a/apps/vben5/packages/@abp/blob-management/package.json +++ b/apps/vben5/packages/@abp/blob-management/package.json @@ -37,13 +37,10 @@ "@vben/locales": "workspace:*", "@vben/stores": "workspace:*", "@vben/utils": "workspace:*", - "@vue-office/docx": "catalog:", - "@vue-office/excel": "catalog:", - "@vue-office/pdf": "catalog:", - "@vue-office/pptx": "catalog:", "ant-design-vue": "catalog:", "vue": "catalog:", "vue-demi": "catalog:", + "vue-files-preview": "catalog:", "vue-simple-uploader": "catalog:", "vxe-table": "catalog:" } diff --git a/apps/vben5/packages/@abp/blob-management/src/api/useBlobsApi.ts b/apps/vben5/packages/@abp/blob-management/src/api/useBlobsApi.ts index f1c109147..9ea8590f7 100644 --- a/apps/vben5/packages/@abp/blob-management/src/api/useBlobsApi.ts +++ b/apps/vben5/packages/@abp/blob-management/src/api/useBlobsApi.ts @@ -32,8 +32,26 @@ export function useBlobsApi() { }); } - function getContentApi(id: string): Promise { - return request(`/api/blob-management/blobs/uid/${id}/content`, { + function generateDownloadUrlApi(id: string): Promise { + return request( + `/api/blob-management/blobs/generate/download-url/${id}`, + { + method: 'GET', + }, + ); + } + + function generatePreviewUrlApi(id: string): Promise { + return request( + `/api/blob-management/blobs/generate/preview-url/${id}`, + { + method: 'GET', + }, + ); + } + + function downloadApi(id: string): Promise { + return request(`/api/blob-management/blobs/download/${id}`, { method: 'GET', responseType: 'blob', }); @@ -70,8 +88,10 @@ export function useBlobsApi() { cancel, createFolderApi, deleteApi, + downloadApi, getApi, - getContentApi, + generateDownloadUrlApi, + generatePreviewUrlApi, getFolderPagedListApi, getFilePagedListApi, getPagedListApi, diff --git a/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal.vue b/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal.vue index 55caa5ddf..69868c3ff 100644 --- a/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal.vue +++ b/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal.vue @@ -64,7 +64,7 @@ const blobType = ref(); const errorMessage = ref(''); const excelComponentKey = ref(0); // 只对 Excel 组件使用 key -const { getContentApi } = useBlobsApi(); +const { downloadApi } = useBlobsApi(); // 文件类型配置 const allowFiles: Record = { @@ -175,7 +175,7 @@ async function onInit() { } // 获取文件内容 - const content = await getContentApi(blob.value.id); + const content = await downloadApi(blob.value.id); // 检查文件大小 if (!isFileSizeValid(content)) { diff --git a/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal1.vue b/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal1.vue new file mode 100644 index 000000000..aac734a60 --- /dev/null +++ b/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal1.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFileTable.vue b/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFileTable.vue index 36dab6532..2d8cdd2ad 100644 --- a/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFileTable.vue +++ b/apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFileTable.vue @@ -35,7 +35,7 @@ const kbUnit = 1 * 1024; const mbUnit = kbUnit * 1024; const gbUnit = mbUnit * 1024; -const { deleteApi, getPagedListApi } = useBlobsApi(); +const { deleteApi, getPagedListApi, generateDownloadUrlApi } = useBlobsApi(); const selectedKeys = ref([]); @@ -169,7 +169,7 @@ const [BlobFileUploadModal, uploadModalApi] = useVbenModal({ }); const [BlobFilePreviewModal, previewModalApi] = useVbenModal({ connectedComponent: defineAsyncComponent( - () => import('./BlobFilePreviewModal.vue'), + () => import('./BlobFilePreviewModal1.vue'), ), }); @@ -191,10 +191,11 @@ function onDownload(row: BlobDto) { centered: true, content: $t('BlobManagement.BlobWellDownloadMessage', [row.name]), onCancel: () => {}, - onOk: () => { + onOk: async () => { + const downloadUrl = await generateDownloadUrlApi(row.id); downloadFileFromUrl({ fileName: row.name, - source: `/api/blob-management/blobs/uid/${row.id}/content`, + source: downloadUrl, }); }, title: $t('AbpUi.AreYouSure'), diff --git a/apps/vben5/pnpm-workspace.yaml b/apps/vben5/pnpm-workspace.yaml index e267880d2..058ee7799 100644 --- a/apps/vben5/pnpm-workspace.yaml +++ b/apps/vben5/pnpm-workspace.yaml @@ -83,6 +83,7 @@ catalog: '@vite-pwa/vitepress': ^1.1.0 '@vitejs/plugin-vue': ^6.0.4 '@vitejs/plugin-vue-jsx': ^5.1.4 + '@vue-files-preview': ^0.0.0 '@vue-office/docx': ^1.6.3 '@vue-office/excel': ^1.7.14 '@vue-office/pdf': ^2.0.10 @@ -235,6 +236,7 @@ catalog: vue: ^3.5.27 vue-demi: ^0.14.6 vue-eslint-parser: ^10.2.0 + vue-files-preview: ^1.0.43 vue-i18n: ^11.2.8 vue-json-viewer: ^3.0.4 vue-router: ^5.0.3 From b4960fa2e4e5ccbac20c5ef7ea49b798e8406feb Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 28 May 2026 16:56:27 +0800 Subject: [PATCH 18/40] feat: Optimize BlobProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 阿里云OSS SDK v4签名存在缺陷, 默认使用v1签名 - 阿里云OSS SDK v2不支持CORS配置, 默认不开启预览, 使用后台代理链接预览文件 - 阿里云BlobProvider增加多个适配SDK v2的配置项 - 腾讯云OSS默认不支持文件预览功能, 需要额外开通数据处理服务, 默认不开启预览, 使用后台代理链接预览文件 --- .../LINGYUN/Abp/Aliyun/AliyunClientFactory.cs | 11 +- .../Aliyun/AliyunBlobNamingNormalizer.cs | 8 +- .../BlobStoring/Aliyun/AliyunBlobProvider.cs | 45 +++--- .../Aliyun/AliyunBlobProviderConfiguration.cs | 67 ++++++++- .../AliyunBlobProviderConfigurationNames.cs | 12 ++ .../BlobStoring/Aliyun/OssClientFactory.cs | 47 +++--- .../Aliyun/AliyunBlobProvider.cs | 136 +++++++++--------- .../Abp/BlobManagement/BlobAppServiceBase.cs | 12 +- .../Tencent/TencentBlobProvider.cs | 88 +++++++----- 9 files changed, 269 insertions(+), 157 deletions(-) diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs index f87b007ca..7071db02d 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/AliyunClientFactory.cs @@ -98,20 +98,19 @@ public abstract class AliyunClientFactory assumeRoleResponse.Body.Credentials.AccessKeySecret, assumeRoleResponse.Body.Credentials.SecurityToken); - var expirationTimeSpan = TimeSpan.FromSeconds(durationSeconds - 10); + var cacheOptions = new DistributedCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(durationSeconds - 10), + }; if (DateTime.TryParse(assumeRoleResponse.Body.Credentials.Expiration, out var expiration)) { cacheItem.Expiration = expiration; - expirationTimeSpan = new TimeSpan(expiration.AddSeconds(-10).Ticks); } await Cache.SetAsync( cacheKey, cacheItem, - new DistributedCacheEntryOptions - { - AbsoluteExpirationRelativeToNow = expirationTimeSpan, - }); + cacheOptions); } return cacheItem; diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobNamingNormalizer.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobNamingNormalizer.cs index 555810724..1e8ffa978 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobNamingNormalizer.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobNamingNormalizer.cs @@ -1,4 +1,5 @@ -using System.Text.RegularExpressions; +using System; +using System.Text.RegularExpressions; using Volo.Abp.BlobStoring; using Volo.Abp.DependencyInjection; @@ -14,7 +15,10 @@ public class AliyunBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDepen /// public virtual string NormalizeBlobName(string blobName) { - return blobName; + // 不能以正斜线(/)或者反斜线(\)开头。 + return blobName + .RemovePreFix("/") + .RemovePreFix("\\"); } /// diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs index af8bd175d..4aa760801 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs @@ -35,7 +35,7 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency public override async Task DeleteAsync(BlobProviderDeleteArgs args) { - var ossClient = await GetOssClientAsync(args); + using var ossClient = await GetOssClientAsync(args); var blobName = AliyunBlobNameCalculator.Calculate(args); if (await BlobExistsAsync(ossClient, args, blobName)) @@ -55,7 +55,7 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency public override async Task ExistsAsync(BlobProviderExistsArgs args) { - var ossClient = await GetOssClientAsync(args); + using var ossClient = await GetOssClientAsync(args); var blobName = AliyunBlobNameCalculator.Calculate(args); return await BlobExistsAsync(ossClient, args, blobName); @@ -63,40 +63,39 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency public override async Task GetOrNullAsync(BlobProviderGetArgs args) { - var ossClient = await GetOssClientAsync(args); + using var ossClient = await GetOssClientAsync(args); var blobName = AliyunBlobNameCalculator.Calculate(args); - if (!await BlobExistsAsync(ossClient, args, blobName)) - { - return null; - } - - var result = await ossClient.GetObjectAsync( - new GetObjectRequest - { - Bucket = GetBucketName(args), - Key = blobName, - }); - return result.Body; + //if (!await BlobExistsAsync(ossClient, args, blobName)) + //{ + // return null; + //} - // TODO: 阿里云sdk预签名不可用[2026/05/23] - //var configuration = args.Configuration.GetAliyunConfiguration(); - //var presignResult = ossClient.Presign( + //var result = await ossClient.GetObjectAsync( // new GetObjectRequest // { // Bucket = GetBucketName(args), // Key = blobName, - // }, - // Clock.Now.AddSeconds(configuration.PresignedGetExpirySeconds)); + // }); + //return result.Body; + + var configuration = args.Configuration.GetAliyunConfiguration(); + var presignResult = ossClient.Presign( + new GetObjectRequest + { + Bucket = GetBucketName(args), + Key = blobName, + }, + Clock.Now.AddSeconds(configuration.PresignedGetExpirySeconds)); - //var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + var httpClient = HttpClientFactory.CreateAliyunHttpClient(); - //return await httpClient.GetStreamAsync(presignResult.Url, args.CancellationToken); + return await httpClient.GetStreamAsync(presignResult.Url, args.CancellationToken); } public override async Task SaveAsync(BlobProviderSaveArgs args) { - var ossClient = await GetOssClientAsync(args); + using var ossClient = await GetOssClientAsync(args); var blobName = AliyunBlobNameCalculator.Calculate(args); var configuration = args.Configuration.GetAliyunConfiguration(); diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs index 2401174e1..8cdf5e126 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs @@ -6,6 +6,22 @@ namespace LINGYUN.Abp.BlobStoring.Aliyun; public class AliyunBlobProviderConfiguration { + /// + /// 默认签名版本 + /// + public const string DefaultSignatureVersion = "v1"; //TODO: 阿里云 OSS SDKv2 SignerV4.ResourcePath存在缺陷, 临时使用v1签名 + /// + /// 默认跳过服务器证书验证 + /// + public const bool DefaultInsecureSkipVerify = false; + /// + /// 默认命名空间不存在是否创建 + /// + public const bool DefaultCreateBucketIfNotExists = false; + /// + /// 默认预签名链接过期时间 + /// + public const int DefaultPresignedGetExpirySeconds = 600; /// /// 命名空间 /// @@ -15,10 +31,18 @@ public class AliyunBlobProviderConfiguration set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.BucketName, value); } /// + /// 签名版本(可选项:v1、v4) + /// 默认: v1 + /// + public string SignatureVersion { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.SignatureVersion, DefaultSignatureVersion); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.SignatureVersion, value); + } + /// /// 跳过服务器证书验证 /// public bool InsecureSkipVerify { - get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.InsecureSkipVerify, false); + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.InsecureSkipVerify, DefaultInsecureSkipVerify); set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.InsecureSkipVerify, value); } /// @@ -26,7 +50,7 @@ public class AliyunBlobProviderConfiguration /// public bool CreateBucketIfNotExists { - get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, false); + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, DefaultCreateBucketIfNotExists); set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, value); } /// @@ -55,15 +79,44 @@ public class AliyunBlobProviderConfiguration } } - /// - /// Default value: 7 * 24 * 3600. - /// + public int PresignedGetExpirySeconds { - get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.PresignedGetExpirySeconds, _defaultExpirySeconds); + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.PresignedGetExpirySeconds, DefaultPresignedGetExpirySeconds); set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.PresignedGetExpirySeconds, value); } - private int _defaultExpirySeconds = 7 * 24 * 3600; + public string Endpoint { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.Endpoint, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint, value); + } + public bool? UsePathStyle { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.UsePathStyle, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.UsePathStyle, value); + } + public bool? UseCName { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.UseCName, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.UseCName, value); + } + public bool? UseDualStackEndpoint { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.UseDualStackEndpoint, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.UseDualStackEndpoint, value); + } + public bool? UseAccelerateEndpoint { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.UseAccelerateEndpoint, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.UseAccelerateEndpoint, value); + } + public bool? UseInternalEndpoint { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.UseInternalEndpoint, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.UseInternalEndpoint, value); + } + public bool? DisableUploadCrc64Check { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.DisableUploadCrc64Check, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.DisableUploadCrc64Check, value); + } + public bool? DisableDownloadCrc64Check { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.DisableDownloadCrc64Check, null); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.DisableDownloadCrc64Check, value); + } private readonly BlobContainerConfiguration _containerConfiguration; diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs index d0bc9f7a7..feb2d7ced 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs @@ -11,6 +11,10 @@ public static class AliyunBlobProviderConfigurationNames /// public const string BucketName = "Aliyun:OSS:BucketName"; /// + /// 签名版本(可选项:v1、v4) + /// + public const string SignatureVersion = "Aliyun:OSS:SignatureVersion"; + /// /// 跳过服务器证书验证 /// public const string InsecureSkipVerify = "Aliyun:OSS:InsecureSkipVerify"; @@ -30,4 +34,12 @@ public static class AliyunBlobProviderConfigurationNames /// 生成预签名Uri的过期时间(s) /// public const string PresignedGetExpirySeconds = "Aliyun:OSS:PresignedGetExpirySeconds"; + + public const string UsePathStyle = "Aliyun:OSS:UsePathStyle"; + public const string UseCName = "Aliyun:OSS:UseCName"; + public const string UseDualStackEndpoint = "Aliyun:OSS:UseDualStackEndpoint"; + public const string UseAccelerateEndpoint = "Aliyun:OSS:UseAccelerateEndpoint"; + public const string UseInternalEndpoint = "Aliyun:OSS:UseInternalEndpoint"; + public const string DisableUploadCrc64Check = "Aliyun:OSS:DisableUploadCrc64Check"; + public const string DisableDownloadCrc64Check = "Aliyun:OSS:DisableDownloadCrc64Check"; } diff --git a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs index 6fc4da256..9faa9ccdb 100644 --- a/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs +++ b/aspnet-core/framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/OssClientFactory.cs @@ -1,5 +1,6 @@ using AlibabaCloud.OSS.V2; using AlibabaCloud.OSS.V2.Credentials; +using AlibabaCloud.OSS.V2.Transport; using LINGYUN.Abp.Aliyun; using System; using Volo.Abp.Caching; @@ -31,10 +32,10 @@ public class OssClientFactory : AliyunClientFactory - { - return new Credentials(accessKeyId, accessKeySecret); - }), + SignatureVersion = AliyunBlobProviderConfiguration.DefaultSignatureVersion, + InsecureSkipVerify = AliyunBlobProviderConfiguration.DefaultInsecureSkipVerify, + CredentialsProvider = new StaticCredentialsProvider(accessKeyId, accessKeySecret), + HttpTransport = HttpTransport.Shared, }); //return new OssClient( // regionId, @@ -56,11 +57,18 @@ public class OssClientFactory : AliyunClientFactory - { - return new Credentials(accessKeyId, accessKeySecret); - }), + Endpoint = configuration.Endpoint, + SignatureVersion = configuration.SignatureVersion, InsecureSkipVerify = configuration.InsecureSkipVerify, + UseCName = configuration.UseCName, + UsePathStyle = configuration.UsePathStyle, + UseAccelerateEndpoint = configuration.UseAccelerateEndpoint, + UseDualStackEndpoint = configuration.UseDualStackEndpoint, + UseInternalEndpoint = configuration.UseInternalEndpoint, + DisableUploadCrc64Check = configuration.DisableUploadCrc64Check, + DisableDownloadCrc64Check = configuration.DisableDownloadCrc64Check, + CredentialsProvider = new StaticCredentialsProvider(accessKeyId, accessKeySecret), + HttpTransport = HttpTransport.Shared, }); } @@ -83,10 +91,10 @@ public class OssClientFactory : AliyunClientFactory - { - return new Credentials(accessKeyId, accessKeySecret, securityToken, expiration); - }), + SignatureVersion = AliyunBlobProviderConfiguration.DefaultSignatureVersion, + InsecureSkipVerify = AliyunBlobProviderConfiguration.DefaultInsecureSkipVerify, + CredentialsProvider = new StaticCredentialsProvider(accessKeyId, accessKeySecret, securityToken), + HttpTransport = HttpTransport.Shared, }); } /// @@ -110,11 +118,18 @@ public class OssClientFactory : AliyunClientFactory - { - return new Credentials(accessKeyId, accessKeySecret, securityToken, expiration); - }), + Endpoint = configuration.Endpoint, + SignatureVersion = configuration.SignatureVersion, InsecureSkipVerify = configuration.InsecureSkipVerify, + UseCName = configuration.UseCName, + UsePathStyle = configuration.UsePathStyle, + UseAccelerateEndpoint = configuration.UseAccelerateEndpoint, + UseDualStackEndpoint = configuration.UseDualStackEndpoint, + UseInternalEndpoint = configuration.UseInternalEndpoint, + DisableUploadCrc64Check = configuration.DisableUploadCrc64Check, + DisableDownloadCrc64Check = configuration.DisableDownloadCrc64Check, + CredentialsProvider = new StaticCredentialsProvider(accessKeyId, accessKeySecret, securityToken), + HttpTransport = HttpTransport.Shared, }); } } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs index fa6af872e..e368e1bda 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Aliyun/LINGYUN/Abp/BlobManagement/Aliyun/AliyunBlobProvider.cs @@ -49,7 +49,7 @@ public class AliyunBlobProvider : IBlobProvider string name, CancellationToken cancellationToken = default) { - var client = await CreateClientAsync(); + using var client = await CreateClientAsync(); var bucket = NormalizeContainerName(name); var configuration = GetBlobConfiguration(); @@ -60,7 +60,7 @@ public class AliyunBlobProvider : IBlobProvider string name, CancellationToken cancellationToken = default) { - var ossClient = await CreateClientAsync(); + using var ossClient = await CreateClientAsync(); var bucket = NormalizeContainerName(name); if (!await BucketExists(ossClient, bucket, cancellationToken)) @@ -81,7 +81,7 @@ public class AliyunBlobProvider : IBlobProvider string blobName, CancellationToken cancellationToken = default) { - var ossClient = await CreateClientAsync(); + using var ossClient = await CreateClientAsync(); var bucket = NormalizeContainerName(containerName); var objectName = CalculateBlobName(blobName); @@ -111,40 +111,39 @@ public class AliyunBlobProvider : IBlobProvider string blobName, CancellationToken cancellationToken = default) { - var ossClient = await CreateClientAsync(); - var bucket = NormalizeContainerName(containerName); - var objectName = CalculateBlobName(blobName); + //using var ossClient = await CreateClientAsync(); + //var bucket = NormalizeContainerName(containerName); + //var objectName = CalculateBlobName(blobName); - if (!await ObjectExists(ossClient, bucket, objectName, cancellationToken)) - { - return null; - } + //if (!await ObjectExists(ossClient, bucket, objectName, cancellationToken)) + //{ + // return null; + //} - var result = await ossClient.GetObjectAsync( - new GetObjectRequest - { - Bucket = bucket, - Key = blobName, - }); + //var result = await ossClient.GetObjectAsync( + // new GetObjectRequest + // { + // Bucket = bucket, + // Key = objectName, + // }); - return result.Body; + //return result.Body; - // TODO: 阿里云sdk预签名不可用[2026/05/23] - //var configuration = GetBlobConfiguration(); + var configuration = GetBlobConfiguration(); - //var downloadUrl = await GeneratePresignedUrlAsync( - // containerName, - // blobName, - // TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), - // cancellationToken: cancellationToken); - //if (downloadUrl.IsNullOrWhiteSpace()) - //{ - // return null; - //} + var downloadUrl = await InternalGeneratePresignedUrlAsync( + containerName, + blobName, + TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), + cancellationToken: cancellationToken); + if (downloadUrl.IsNullOrWhiteSpace()) + { + return null; + } - //var httpClient = HttpClientFactory.CreateAliyunHttpClient(); + var httpClient = HttpClientFactory.CreateAliyunHttpClient(); - //return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); + return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); } public virtual Task GeneratePresignedUrlAsync( @@ -154,32 +153,14 @@ public class AliyunBlobProvider : IBlobProvider bool isAttachmentContent = true, CancellationToken cancellationToken = default) { - // TODO: 阿里云sdk预签名不可用[2026/05/23] + // TODO: 阿里云SDK2.0不支持Bucket跨域配置, 不启用阿里云的预览方式 + //return InternalGeneratePresignedUrlAsync( + // containerName, + // blobName, + // expiration, + // isAttachmentContent, + // cancellationToken); return Task.FromResult(null); - //var ossClient = await CreateClientAsync(); - //var bucket = NormalizeContainerName(containerName); - //var objectName = CalculateBlobName(blobName); - - //if (!await ObjectExists(ossClient, bucket, objectName, cancellationToken)) - //{ - // return null; - //} - - //var fileName = Path.GetFileName(blobName); - //var type = isAttachmentContent ? "attachment" : "inline"; - //var disposition = $"{type}; filename=\"{Uri.EscapeDataString(fileName)}\"; " + - // $"filename*=UTF-8''{Uri.EscapeDataString(fileName)}"; - - //var presignResult = ossClient.Presign( - // new GetObjectRequest - // { - // Bucket = bucket, - // Key = blobName, - // ResponseContentDisposition = disposition, - // }, - // Clock.Now.Add(expiration)); - - //return presignResult.Url; } public virtual Task CreateFolderAsync( @@ -199,7 +180,7 @@ public class AliyunBlobProvider : IBlobProvider string? contentType = null, CancellationToken cancellationToken = default) { - var ossClient = await CreateClientAsync(); + using var ossClient = await CreateClientAsync(); var bucket = NormalizeContainerName(containerName); var objectName = CalculateBlobName(blobName); var configuration = GetBlobConfiguration(); @@ -241,20 +222,43 @@ public class AliyunBlobProvider : IBlobProvider new PutBucketRequest { Bucket = bucket, + Acl = bucketAcl?.GetString(), }, cancellationToken: cancellationToken); + } + } - if (bucketAcl.HasValue) - { - await ossClient.PutBucketAclAsync( - new PutBucketAclRequest - { - Bucket = bucket, - Acl = bucketAcl.Value.GetString(), - }, - cancellationToken: cancellationToken); - } + protected async virtual Task InternalGeneratePresignedUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + bool isAttachmentContent = true, + CancellationToken cancellationToken = default) + { + using var ossClient = await CreateClientAsync(); + var bucket = NormalizeContainerName(containerName); + var objectName = CalculateBlobName(blobName); + + if (!await ObjectExists(ossClient, bucket, objectName, cancellationToken)) + { + return null; } + + var fileName = Path.GetFileName(blobName); + var type = isAttachmentContent ? "attachment" : "inline"; + var disposition = $"{type}; filename=\"{Uri.EscapeDataString(fileName)}\"; " + + $"filename*=UTF-8''{Uri.EscapeDataString(fileName)}"; + + var presignResult = ossClient.Presign( + new GetObjectRequest + { + Bucket = bucket, + Key = objectName, + ResponseContentDisposition = disposition, + }, + Clock.Now.Add(expiration)); + + return presignResult.Url; } protected async virtual Task BucketExists( diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs index 638234cf8..ecff6b46d 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobAppServiceBase.cs @@ -64,7 +64,11 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService var stream = await BlobManager.DownloadBlobsync(blob); - return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); + return new RemoteStreamContent( + stream ?? Stream.Null, + blob.Name, + blob.ContentType, + stream != null ? blob.Size : null); } public async virtual Task GetAsync(Guid id) @@ -169,7 +173,11 @@ public abstract class BlobAppServiceBase : BlobManagementApplicationService var stream = await BlobManager.DownloadBlobsync(blob); - return new RemoteStreamContent(stream ?? Stream.Null, blob.Name, blob.ContentType, stream?.Length); + return new RemoteStreamContent( + stream ?? Stream.Null, + blob.Name, + blob.ContentType, + stream != null ? blob.Size : null); } protected async virtual Task GenerateDownloadUrlAsync(Guid id, string method, bool isAttachmentContent = true) diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs index acdac8f47..54ae39fa8 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN/Abp/BlobManagement/Tencent/TencentBlobProvider.cs @@ -104,7 +104,7 @@ public class TencentBlobProvider : IBlobProvider { var configuration = await GetBlobConfiguration(); - var downloadUrl = await GeneratePresignedUrlAsync( + var downloadUrl = await InternalGeneratePresignedUrlAsync( containerName, blobName, TimeSpan.FromSeconds(configuration.PresignedGetExpirySeconds), @@ -119,11 +119,61 @@ public class TencentBlobProvider : IBlobProvider return await httpClient.GetStreamAsync(downloadUrl, cancellationToken); } - public async virtual Task GeneratePresignedUrlAsync( + public virtual Task GeneratePresignedUrlAsync( string containerName, string blobName, TimeSpan expiration, - bool isAttachmentContent = true, + bool isAttachmentContent = true, + CancellationToken cancellationToken = default) + { + // TODO: 腾讯云需用户开通对象处理服务以支持预览, 不启用腾讯云的预览方式. + //return InternalGeneratePresignedUrlAsync( + // containerName, + // blobName, + // expiration, + // isAttachmentContent, + // cancellationToken); + + return Task.FromResult(null); + } + + public virtual Task CreateFolderAsync( + string containerName, + string blobName, + CancellationToken cancellationToken = default) + { + // 腾讯云Oss没有目录的概念,新建对象时可以模拟目录 + // https://cloud.tencent.com/document/product/436/13324 + return Task.CompletedTask; + } + + public async virtual Task UploadBlobAsync( + string containerName, + string blobName, + Stream content, + string? contentType = null, + CancellationToken cancellationToken = default) + { + var client = await CreateClientAsync(); + var bucket = NormalizeContainerName(containerName); + var objectName = CalculateBlobName(blobName); + + CreateBucketIfNotExists(client, bucket); + + var putObjectRequest = new PutObjectRequest(bucket, objectName, content); + if (!contentType.IsNullOrWhiteSpace()) + { + putObjectRequest.SetRequestHeader("Content-Type", contentType); + } + + client.PutObject(putObjectRequest); + } + + protected async virtual Task InternalGeneratePresignedUrlAsync( + string containerName, + string blobName, + TimeSpan expiration, + bool isAttachmentContent = true, CancellationToken cancellationToken = default) { var client = await CreateClientAsync(); @@ -161,38 +211,6 @@ public class TencentBlobProvider : IBlobProvider return client.GenerateSignURL(preSignatureStruct); } - public virtual Task CreateFolderAsync( - string containerName, - string blobName, - CancellationToken cancellationToken = default) - { - // 腾讯云Oss没有目录的概念,新建对象时可以模拟目录 - // https://cloud.tencent.com/document/product/436/13324 - return Task.CompletedTask; - } - - public async virtual Task UploadBlobAsync( - string containerName, - string blobName, - Stream content, - string? contentType = null, - CancellationToken cancellationToken = default) - { - var client = await CreateClientAsync(); - var bucket = NormalizeContainerName(containerName); - var objectName = CalculateBlobName(blobName); - - CreateBucketIfNotExists(client, bucket); - - var putObjectRequest = new PutObjectRequest(bucket, objectName, content); - if (!contentType.IsNullOrWhiteSpace()) - { - putObjectRequest.SetRequestHeader("Content-Type", contentType); - } - - client.PutObject(putObjectRequest); - } - protected async virtual Task CreateClientAsync() { return await CosClientFactory.CreateAsync(); From 511eae2d2a3d4b02a8e50adb041a3c60ba8ca6ea Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 28 May 2026 16:59:57 +0800 Subject: [PATCH 19/40] fix: Fix the issue of sending duplicate SMS verification codes - Fix the prompt for repeated sending of SMS verification code messages --- .../LINGYUN/Abp/Account/MyProfileAppService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs index b0613662d..c0008d913 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs @@ -140,7 +140,7 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS var interval = await SettingProvider.GetAsync(Identity.Settings.IdentitySettingNames.User.SmsRepetInterval, 1); if (securityTokenCacheItem != null) { - throw new UserFriendlyException(L["SendRepeatPhoneVerifyCode", interval]); + throw new UserFriendlyException(L["SendRepeatSmsVerifyCode", interval]); } // 是否已有用户使用手机号绑定 From c94b09841527d9e5b60d18f2f10fdcee67363b78 Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 28 May 2026 17:01:07 +0800 Subject: [PATCH 20/40] fix: Fix the MySQL token cleanup issue - After querying the expired token collection, then delete it --- ...igrationsEntityFrameworkCoreMySqlModule.cs | 7 ++++ .../EfCoreMySqlOpenIddictTokenRepository.cs | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Volo/Abp/OpenIddict/Tokens/EfCoreMySqlOpenIddictTokenRepository.cs diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/SingleMigrationsEntityFrameworkCoreMySqlModule.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/SingleMigrationsEntityFrameworkCoreMySqlModule.cs index d9187af38..d09ca5c43 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/SingleMigrationsEntityFrameworkCoreMySqlModule.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/SingleMigrationsEntityFrameworkCoreMySqlModule.cs @@ -8,6 +8,8 @@ using System; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Guids; using Volo.Abp.Modularity; +using Volo.Abp.OpenIddict.EntityFrameworkCore; +using Volo.Abp.OpenIddict.Tokens; namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql; @@ -64,6 +66,11 @@ public class SingleMigrationsEntityFrameworkCoreMySqlModule : AbpModule options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString; } }); + + context.Services.AddAbpDbContext(options => + { + options.AddRepository(); + }); } } } diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Volo/Abp/OpenIddict/Tokens/EfCoreMySqlOpenIddictTokenRepository.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Volo/Abp/OpenIddict/Tokens/EfCoreMySqlOpenIddictTokenRepository.cs new file mode 100644 index 000000000..c5385f120 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Volo/Abp/OpenIddict/Tokens/EfCoreMySqlOpenIddictTokenRepository.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using OpenIddict.Abstractions; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.OpenIddict.Authorizations; +using Volo.Abp.OpenIddict.EntityFrameworkCore; + +namespace Volo.Abp.OpenIddict.Tokens; + +public class EfCoreMySqlOpenIddictTokenRepository : EfCoreOpenIddictTokenRepository +{ + public EfCoreMySqlOpenIddictTokenRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async override Task PruneAsync(DateTime date, CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var tokens = await (from token in dbContext.Set() + join authorization in dbContext.Set() + on token.AuthorizationId equals authorization.Id into tokenAuthorizations + from tokenAuthorization in tokenAuthorizations.DefaultIfEmpty() + where token.CreationDate < date + where (token.Status != OpenIddictConstants.Statuses.Inactive && token.Status != OpenIddictConstants.Statuses.Valid) || + (tokenAuthorization != null && tokenAuthorization.Status != OpenIddictConstants.Statuses.Valid) || + token.ExpirationDate < DateTime.UtcNow + select token) + .ToListAsync(GetCancellationToken(cancellationToken)); + + await DeleteManyAsync(tokens, cancellationToken: GetCancellationToken(cancellationToken)); + + return tokens.Count; + } +} From ac754c7b82e03a5c76cdd3f47cff7d3053657c68 Mon Sep 17 00:00:00 2001 From: colin Date: Sat, 30 May 2026 15:46:06 +0800 Subject: [PATCH 21/40] feat(identity): Add checks for inactive users' jobs - Add the notification job for inactive users - Increase the operation for cleaning inactive users - Increase the number of inactive user entities --- aspnet-core/LINGYUN.MicroService.All.slnx | 2 + aspnet-core/LINGYUN.MicroService.Aspire.slnx | 1 + .../LINGYUN.MicroService.SingleProject.slnx | 1 + .../AuthServerMigrationsDbContext.cs | 3 + ...327_Add-Identity-User-Inactive.Designer.cs | 1403 ++++ ...260530060327_Add-Identity-User-Inactive.cs | 48 + ...hServerMigrationsDbContextModelSnapshot.cs | 42 + ...rSubscribeSessionExpirationEventHandler.cs | 9 +- ...ice.TaskService.EntityFrameworkCore.csproj | 3 - ...viceMigrationsEntityFrameworkCoreModule.cs | 6 - ...INGYUN.Abp.MicroService.TaskService.csproj | 2 + .../TaskServiceModule.cs | 4 + ...257_Add-Identity-User-Inactive.Designer.cs | 6179 ++++++++++++++++ ...260529063257_Add-Identity-User-Inactive.cs | 49 + .../SingleMigrationsDbContextModelSnapshot.cs | 42 + ...941_Add-Identity-User-Inactive.Designer.cs | 6179 ++++++++++++++++ ...260530055941_Add-Identity-User-Inactive.cs | 48 + .../SingleMigrationsDbContextModelSnapshot.cs | 42 + ...009_Add-Identity-User-Inactive.Designer.cs | 6186 +++++++++++++++++ ...260530060009_Add-Identity-User-Inactive.cs | 47 + .../SingleMigrationsDbContextModelSnapshot.cs | 42 + .../SingleMigrationsDbContext.cs | 4 +- .../AuthServerMigrationsDbContext.cs | 3 + ...141_Add-Identity-User-Inactive.Designer.cs | 1417 ++++ ...260530061141_Add-Identity-User-Inactive.cs | 49 + ...hServerMigrationsDbContextModelSnapshot.cs | 42 + .../Account/AbpAccountApplicationModule.cs | 1 + .../Abp/Account/Security/AccountUrlNames.cs | 1 + .../Abp/Identity/IdentityUserAppService.cs | 8 + .../Abp/Identity/InactiveUserStatus.cs | 7 + .../LINGYUN/Abp/Identity/Localization/en.json | 4 + .../Abp/Identity/Localization/zh-Hans.json | 4 + .../IdentitySettingDefinitionProvider.cs | 12 + .../Identity/Settings/IdentitySettingNames.cs | 9 + .../Abp/Identity/AbpIdentityDomainModule.cs | 1 + .../IIdentityUserInactiveRepository.cs | 40 + .../Abp/Identity/IIdentityUserRepository.cs | 2 +- .../Abp/Identity/IdentityUserInactive.cs | 48 + ...IdentitySessionUserInactiveSynchronizer.cs | 29 + .../AbpIdentityEntityFrameworkCoreModule.cs | 38 +- .../EfCoreIdentityUserInactiveRepository.cs | 100 + ...InactiveDbContextModelBuilderExtensions.cs | 23 + .../LINGYUN.Abp.Identity.Notifications.csproj | 7 + .../AbpIdentityNotificationsModule.cs | 16 + .../IdentityNotificationDefinitionProvider.cs | 22 +- .../IdentityNotificationNames.cs | 12 +- .../Localization/Resources/en.json | 29 + .../Localization/Resources/zh-Hans.json | 29 + ...yNotificationTemplateDefinitionProvider.cs | 34 + .../InactiveUserDeactivationNotifier.tpl | 33 + .../InactiveUserDeletionNotifier.tpl | 30 + .../InactiveUserReminderNotifier.tpl | 36 + .../SettingManagement/SettingAppService.cs | 40 +- .../LINGYUN.Abp.Identity.Jobs.csproj | 4 + .../Identity/Jobs/AbpIdentityJobsModule.cs | 4 +- .../Jobs/IdentityJobDefinitionProvider.cs | 17 +- .../Jobs/InactiveIdentityUserCleanupJob.cs | 418 +- .../Jobs/InactiveIdentityUserNotifierJob.cs | 179 + .../Jobs/Localization/Resources/en.json | 7 +- .../Jobs/Localization/Resources/zh-Hans.json | 7 +- ...scribeIdentityNotificationsEventHandler.cs | 39 + ...LY.MicroService.Applications.Single.csproj | 1 + .../MicroServiceApplicationsSingleModule.cs | 3 + ...rSubscribeSessionExpirationEventHandler.cs | 9 +- ...Service.TaskManagement.HttpApi.Host.csproj | 3 + .../TaskManagementHttpApiHostModule.cs | 8 +- 66 files changed, 22991 insertions(+), 176 deletions(-) create mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.Designer.cs create mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.cs create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.Designer.cs create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.cs create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.Designer.cs create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.cs create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.Designer.cs create mode 100644 aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.cs create mode 100644 aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530061141_Add-Identity-User-Inactive.Designer.cs create mode 100644 aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530061141_Add-Identity-User-Inactive.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/InactiveUserStatus.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserInactiveRepository.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityUserInactive.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserInactiveRepository.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/IdentityUserInactiveDbContextModelBuilderExtensions.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/en.json create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/zh-Hans.json create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/IdentityNotificationTemplateDefinitionProvider.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeactivationNotifier.tpl create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeletionNotifier.tpl create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserReminderNotifier.tpl create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserNotifierJob.cs create mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Local/UserCreateSubscribeIdentityNotificationsEventHandler.cs diff --git a/aspnet-core/LINGYUN.MicroService.All.slnx b/aspnet-core/LINGYUN.MicroService.All.slnx index a990dac8d..64367e62e 100644 --- a/aspnet-core/LINGYUN.MicroService.All.slnx +++ b/aspnet-core/LINGYUN.MicroService.All.slnx @@ -377,6 +377,7 @@ + @@ -484,6 +485,7 @@ + diff --git a/aspnet-core/LINGYUN.MicroService.Aspire.slnx b/aspnet-core/LINGYUN.MicroService.Aspire.slnx index f44c32ec2..f247470fb 100644 --- a/aspnet-core/LINGYUN.MicroService.Aspire.slnx +++ b/aspnet-core/LINGYUN.MicroService.Aspire.slnx @@ -496,6 +496,7 @@ + diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.slnx b/aspnet-core/LINGYUN.MicroService.SingleProject.slnx index 5e401511a..77245068b 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.slnx +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.slnx @@ -282,6 +282,7 @@ + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs index f38674d4a..72956c22a 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs @@ -1,5 +1,6 @@ using LINGYUN.Abp.Gdpr; using LINGYUN.Abp.Gdpr.EntityFrameworkCore; +using LINGYUN.Abp.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -59,5 +60,7 @@ public class AuthServerMigrationsDbContext : modelBuilder.ConfigureIdentity(); modelBuilder.ConfigureOpenIddict(); modelBuilder.ConfigureGdpr(); + + modelBuilder.ConfigureIdentityUserInactive(); } } diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.Designer.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.Designer.cs new file mode 100644 index 000000000..f1c69acc5 --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.Designer.cs @@ -0,0 +1,1403 @@ +// +using System; +using LINGYUN.Abp.MicroService.AuthServer; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LINGYUN.Abp.MicroService.AuthServer.Migrations +{ + [DbContext(typeof(AuthServerMigrationsDbContext))] + [Migration("20260530060327_Add-Identity-User-Inactive")] + partial class AddIdentityUserInactive + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text") + .HasColumnName("Data"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Provider"); + + b.Property("RequestId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RequestId"); + + b.ToTable("AbpGdprInfos", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("ReadyTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpGdprRequests", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastNotificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("SourceTenantId") + .HasColumnType("uuid"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("TargetTenantId") + .HasColumnType("uuid"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique(); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("boolean") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("boolean") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("LastAccessed") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("SignedIn") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("boolean"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("character varying(196)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("bytea"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("AbpUserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("character varying(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ClientSecret") + .HasColumnType("text"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ClientUri") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("DisplayNames") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("JsonWebKeySet") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LogoUri") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("text"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("RedirectUris") + .HasColumnType("text"); + + b.Property("Requirements") + .HasColumnType("text"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("OpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("Scopes") + .HasColumnType("text"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Scopes.OpenIddictScope", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Descriptions") + .HasColumnType("text"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("DisplayNames") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("Resources") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("OpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AuthorizationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("RedemptionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("Type") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null) + .WithMany("Infos") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("AbpUserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("jsonb"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + + b.HasOne("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", null) + .WithMany() + .HasForeignKey("AuthorizationId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Navigation("Infos"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.cs new file mode 100644 index 000000000..3b6aa1684 --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace LINGYUN.Abp.MicroService.AuthServer.Migrations +{ + /// + public partial class AddIdentityUserInactive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpUserInactives", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + LastSignInTime = table.Column(type: "timestamp with time zone", nullable: false), + LastNotificationTime = table.Column(type: "timestamp with time zone", nullable: true), + Status = table.Column(type: "integer", nullable: false), + DeactivatedTime = table.Column(type: "timestamp with time zone", nullable: true), + CreationTime = table.Column(type: "timestamp with time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserInactives", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserInactives_TenantId_UserId", + table: "AbpUserInactives", + columns: new[] { "TenantId", "UserId" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpUserInactives"); + } + } +} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs index 899ae3538..85e72e195 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs @@ -84,6 +84,48 @@ namespace LINGYUN.Abp.MicroService.AuthServer.Migrations b.ToTable("AbpGdprRequests", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastNotificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Local/UserSubscribeSessionExpirationEventHandler.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Local/UserSubscribeSessionExpirationEventHandler.cs index aea56ee94..0827ebf7e 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Local/UserSubscribeSessionExpirationEventHandler.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Local/UserSubscribeSessionExpirationEventHandler.cs @@ -25,11 +25,16 @@ public class UserSubscribeSessionExpirationEventHandler : ILocalEventHandlerruntime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService.EntityFrameworkCore/TaskServiceMigrationsEntityFrameworkCoreModule.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService.EntityFrameworkCore/TaskServiceMigrationsEntityFrameworkCoreModule.cs index 321d29450..ebcb8db9e 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService.EntityFrameworkCore/TaskServiceMigrationsEntityFrameworkCoreModule.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService.EntityFrameworkCore/TaskServiceMigrationsEntityFrameworkCoreModule.cs @@ -6,10 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using System; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.PostgreSql; -using Volo.Abp.FeatureManagement.EntityFrameworkCore; using Volo.Abp.Modularity; -using Volo.Abp.PermissionManagement.EntityFrameworkCore; -using Volo.Abp.SettingManagement.EntityFrameworkCore; namespace LINGYUN.Abp.MicroService.TaskService; @@ -18,9 +15,6 @@ namespace LINGYUN.Abp.MicroService.TaskService; typeof(AbpSaasEntityFrameworkCoreModule), typeof(TaskManagementEntityFrameworkCoreModule), typeof(AbpEntityFrameworkCorePostgreSqlModule), - typeof(AbpSettingManagementEntityFrameworkCoreModule), - typeof(AbpPermissionManagementEntityFrameworkCoreModule), - typeof(AbpFeatureManagementEntityFrameworkCoreModule), typeof(AbpDataDbMigratorModule) )] public class TaskServiceMigrationsEntityFrameworkCoreModule : AbpModule diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/LINGYUN.Abp.MicroService.TaskService.csproj b/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/LINGYUN.Abp.MicroService.TaskService.csproj index 1f21f5504..c79164c87 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/LINGYUN.Abp.MicroService.TaskService.csproj +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/LINGYUN.Abp.MicroService.TaskService.csproj @@ -55,7 +55,9 @@ + + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/TaskServiceModule.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/TaskServiceModule.cs index 5a266fbaa..0c735e7cf 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/TaskServiceModule.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.TaskService/TaskServiceModule.cs @@ -14,6 +14,8 @@ using LINGYUN.Abp.Elasticsearch.Jobs; using LINGYUN.Abp.Emailing.Platform; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.Identity.EntityFrameworkCore; +using LINGYUN.Abp.Identity.Jobs; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.Saas.EntityFrameworkCore; @@ -54,6 +56,7 @@ namespace LINGYUN.Abp.MicroService.TaskService; typeof(AbpAspNetCoreMultiTenancyModule), typeof(AbpAspNetCoreMvcLocalizationModule), typeof(AbpElasticsearchJobsModule), + typeof(AbpIdentityJobsModule), typeof(AbpBackgroundTasksJobsModule), typeof(AbpBackgroundTasksQuartzModule), typeof(AbpBackgroundTasksDistributedLockingModule), @@ -61,6 +64,7 @@ namespace LINGYUN.Abp.MicroService.TaskService; typeof(TaskManagementApplicationModule), typeof(TaskManagementHttpApiModule), typeof(TaskManagementEntityFrameworkCoreModule), + typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpFeatureManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.Designer.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.Designer.cs new file mode 100644 index 000000000..56d735da0 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.Designer.cs @@ -0,0 +1,6179 @@ +// +using System; +using LY.MicroService.Applications.Single.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations +{ + [DbContext(typeof(SingleMigrationsDbContext))] + [Migration("20260529063257_Add-Identity-User-Inactive")] + partial class AddIdentityUserInactive + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "10.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExpiredAt") + .HasColumnType("datetime(6)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UpdateAt") + .HasColumnType("datetime(6)"); + + b.Property("Workspace") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("Id"); + + b.ToTable("AbpAIConversations", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.Property("ConversationId") + .HasColumnType("char(36)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("ReplyAt") + .HasColumnType("datetime(6)"); + + b.Property("ReplyMessage") + .HasColumnType("longtext"); + + b.Property("Role") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("Workspace") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ConversationId"); + + b.ToTable("AbpAITextChatMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CachedInputTokenCount") + .HasColumnType("bigint"); + + b.Property("ConversationId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("InputTokenCount") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MessageId") + .HasColumnType("char(36)"); + + b.Property("OutputTokenCount") + .HasColumnType("bigint"); + + b.Property("ReasoningTokenCount") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TotalTokenCount") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ConversationId"); + + b.ToTable("AbpAITokenUsages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tools.AIToolDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("IsGlobal") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpAIAIToolDefinitionRecords", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiBaseUrl") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ApiKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FrequencyPenalty") + .HasColumnType("float"); + + b.Property("Instructions") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("IsSystem") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MaxOutputTokens") + .HasColumnType("int"); + + b.Property("ModelName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("PresencePenalty") + .HasColumnType("float"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("SystemPrompt") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("Temperature") + .HasColumnType("float"); + + b.Property("Tools") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpAIWorkspaceDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("char(36)"); + + b.Property("ContentType") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("bigint"); + + b.Property("ExpirationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("ParentId"); + + b.HasIndex("TenantId", "ContainerId", "FullName"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.BlobContainer", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("PropertyInfoId") + .HasColumnType("char(36)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("varchar(10)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("PropertyInfoId", "Name"); + + b.ToTable("AbpAuthEntityEnums", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("JavaScriptType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("JavaScriptType"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.SubjectStrategy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Strategy") + .HasColumnType("int"); + + b.Property("SubjectId") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("SubjectId"); + + b.Property("SubjectName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("SubjectName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuthSubjectStrategys", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Authors.Author", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BirthDate") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ShortBio") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Demo_Authors", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AuthorId") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Price") + .HasColumnType("float"); + + b.Property("PublishDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Demo_Books", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("EntityId") + .HasMaxLength(64) + .HasColumnType("char(64)") + .HasColumnName("EntityId"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("EntityType"); + + b.Property("OrganizationUnit") + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("OrganizationUnit"); + + b.Property("Role") + .HasMaxLength(32) + .HasColumnType("varchar(32)") + .HasColumnName("Role"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("EntityId"); + + b.HasIndex("OrganizationUnit"); + + b.HasIndex("Role"); + + b.ToTable("Demo_BooksAuths", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Data"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Provider"); + + b.Property("RequestId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("RequestId"); + + b.ToTable("AbpGdprInfos", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("ReadyTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpGdprRequests", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("datetime(6)"); + + b.Property("LastNotificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastSignInTime") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("CultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("TwoLetterISOLanguageName") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("TwoLetterISOLanguageName"); + + b.Property("UiCultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("UiCultureName"); + + b.HasKey("Id"); + + b.HasIndex("CultureName"); + + b.ToTable("AbpLocalizationLanguages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Resource", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DefaultCultureName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("DefaultCultureName"); + + b.Property("Description") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpLocalizationResources", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Text", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("CultureName"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("Key"); + + b.Property("ResourceName") + .HasColumnType("longtext"); + + b.Property("Value") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("AbpLocalizationTexts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("AvatarUrl") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("Birthday") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LastOnlineTime") + .HasColumnType("datetime(6)"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Sex") + .HasColumnType("int"); + + b.Property("Sign") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatFriend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Black") + .HasColumnType("tinyint(1)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("DontDisturb") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FrientId") + .HasColumnType("char(36)"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("RemarkName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("SpecialFocus") + .HasColumnType("tinyint(1)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "FrientId"); + + b.ToTable("AppUserChatFriends", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AllowAddFriend") + .HasColumnType("tinyint(1)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowReceiveMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("RequireAddFriendValition") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("longtext"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("char(36)"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("AdminUserId") + .HasColumnType("char(36)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AvatarUrl") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("Notice") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Tag") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("longtext"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserGroupCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAdmin") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("SilenceEnd") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserGroupCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ContentType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("ExpirationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("NotificationTypeName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("Severity") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName"); + + b.ToTable("AppNotifications", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionGroupRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AllowSubscriptionToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.ToTable("AppNotificationDefinitionGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AllowSubscriptionToClients") + .HasColumnType("tinyint(1)"); + + b.Property("ContentType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("NotificationLifetime") + .HasColumnType("int"); + + b.Property("NotificationType") + .HasColumnType("int"); + + b.Property("Providers") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Template") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.ToTable("AppNotificationDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Reason") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("SendTime") + .HasColumnType("datetime(6)"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName") + .HasDatabaseName("IX_Tenant_Send_Notification_Name"); + + b.ToTable("AppNotificationSendRecords", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("ReadStatus") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationId") + .HasDatabaseName("IX_Tenant_User_Notification_Id"); + + b.ToTable("AppUserNotifications", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.UserSubscribe", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationName") + .IsUnique() + .HasDatabaseName("IX_Tenant_User_Notification_Name"); + + b.ToTable("AppUserSubscribes", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Editions.Edition", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.ToTable("AbpEditions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisableTime") + .HasColumnType("datetime(6)"); + + b.Property("EditionId") + .HasColumnType("char(36)"); + + b.Property("EnableTime") + .HasColumnType("datetime(6)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("NormalizedName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("EditionId"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpTenants", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobAction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("JobId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("JobId"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Name"); + + b.Property("Paramters") + .HasColumnType("longtext") + .HasColumnName("Paramters"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("TK_BackgroundJobActions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobInfo", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("Args") + .HasColumnType("longtext") + .HasColumnName("Args"); + + b.Property("BeginTime") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Cron") + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("Cron"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Description"); + + b.Property("EndTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Group") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Group"); + + b.Property("Interval") + .HasColumnType("int"); + + b.Property("IsAbandoned") + .HasColumnType("tinyint(1)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("JobType") + .HasColumnType("int"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LastRunTime") + .HasColumnType("datetime(6)"); + + b.Property("LockTimeOut") + .HasColumnType("int"); + + b.Property("MaxCount") + .HasColumnType("int"); + + b.Property("MaxTryCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Name"); + + b.Property("NextRunTime") + .HasColumnType("datetime(6)"); + + b.Property("NodeName") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("NodeName"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Result") + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("Result"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TriggerCount") + .HasColumnType("int"); + + b.Property("TryCount") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("Type"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Group"); + + b.ToTable("TK_BackgroundJobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Exception") + .HasMaxLength(2000) + .HasColumnType("varchar(2000)") + .HasColumnName("Exception"); + + b.Property("JobGroup") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("JobGroup"); + + b.Property("JobId") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("JobId"); + + b.Property("JobName") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("JobName"); + + b.Property("JobType") + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("JobType"); + + b.Property("Message") + .HasMaxLength(1000) + .HasColumnType("varchar(1000)") + .HasColumnName("Message"); + + b.Property("RunTime") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("JobGroup", "JobName"); + + b.ToTable("TK_BackgroundJobLogs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplate", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Content") + .HasMaxLength(1048576) + .HasColumnType("longtext") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Culture") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Culture"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("DisplayName"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .HasDatabaseName("IX_Tenant_Text_Template_Name"); + + b.ToTable("AbpTextTemplates", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplateDefinition", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultCultureName") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("DefaultCultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsInlineLocalized") + .HasColumnType("tinyint(1)"); + + b.Property("IsLayout") + .HasColumnType("tinyint(1)"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Layout") + .HasMaxLength(60) + .HasColumnType("varchar(60)") + .HasColumnName("Layout"); + + b.Property("LocalizationResourceName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("LocalizationResourceName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Name"); + + b.Property("RenderEngine") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("RenderEngine"); + + b.HasKey("Id"); + + b.ToTable("AbpTextTemplateDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("RequiredFeatures") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpWebhooksWebhooks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookEventRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("Data") + .HasMaxLength(2147483647) + .HasColumnType("longtext") + .HasColumnName("Data"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WebhookName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("WebhookName"); + + b.HasKey("Id"); + + b.ToTable("AbpWebhooksEvents", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpWebhooksWebhookGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("RequestHeaders") + .HasMaxLength(2147483647) + .HasColumnType("longtext") + .HasColumnName("RequestHeaders"); + + b.Property("Response") + .HasMaxLength(2147483647) + .HasColumnType("longtext") + .HasColumnName("Response"); + + b.Property("ResponseHeaders") + .HasMaxLength(2147483647) + .HasColumnType("longtext") + .HasColumnName("ResponseHeaders"); + + b.Property("ResponseStatusCode") + .HasColumnType("int"); + + b.Property("SendExactSameData") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("WebhookEventId") + .HasColumnType("char(36)"); + + b.Property("WebhookSubscriptionId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("WebhookEventId"); + + b.ToTable("AbpWebhooksSendAttempts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Description"); + + b.Property("Headers") + .HasMaxLength(2147483647) + .HasColumnType("longtext") + .HasColumnName("Headers"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("Secret") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Secret"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("TimeoutDuration") + .HasColumnType("int"); + + b.Property("WebhookUri") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("WebhookUri"); + + b.Property("Webhooks") + .HasMaxLength(2147483647) + .HasColumnType("longtext") + .HasColumnName("Webhooks"); + + b.HasKey("Id"); + + b.ToTable("AbpWebhooksSubscriptions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.Data", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Name"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AppPlatformDatas", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.DataItem", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AllowBeNull") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DataId") + .HasColumnType("char(36)"); + + b.Property("DefaultValue") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DefaultValue"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Name"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("DataId"); + + b.HasIndex("Name"); + + b.ToTable("AppPlatformDataItems", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Category"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformFeedbacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("FeedbackId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Url"); + + b.HasKey("Id"); + + b.HasIndex("FeedbackId"); + + b.ToTable("AppPlatformFeedbackAttachments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Capacity") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Capacity"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("FeedbackId") + .HasColumnType("char(36)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("FeedbackId"); + + b.ToTable("AppPlatformFeedbackComments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DataId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Framework"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("Path") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Path"); + + b.Property("Redirect") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Redirect"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformLayouts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.Menu", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(23) + .HasColumnType("varchar(23)") + .HasColumnName("Code"); + + b.Property("Component") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Component"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Framework"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsPublic") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LayoutId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("Path") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Path"); + + b.Property("Redirect") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Redirect"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.RoleMenu", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("char(36)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("RoleName"); + + b.Property("Startup") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleName", "MenuId"); + + b.ToTable("AppPlatformRoleMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.UserFavoriteMenu", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AliasName") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("AliasName"); + + b.Property("Color") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Color"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Framework"); + + b.Property("Icon") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("Icon"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Path"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "MenuId"); + + b.ToTable("AppPlatformUserFavoriteMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.UserMenu", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("char(36)"); + + b.Property("Startup") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "MenuId"); + + b.ToTable("AppPlatformUserMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessage", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BodyTransferEncoding") + .HasColumnType("int"); + + b.Property("CC") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("CC"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeliveryNotificationOptions") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("From") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("From"); + + b.Property("IsBodyHtml") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Normalize") + .HasColumnType("tinyint(1)"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Provider") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Provider"); + + b.Property("Reason") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Reason"); + + b.Property("Receiver") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Receiver"); + + b.Property("SendCount") + .HasColumnType("int"); + + b.Property("SendTime") + .HasColumnType("datetime(6)"); + + b.Property("Sender") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Sender"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Subject") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Subject"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformEmailMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("BlobName"); + + b.Property("MessageId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Name"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("AppPlatformEmailMessageAttachments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Key") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Key"); + + b.Property("MessageId") + .HasColumnType("char(36)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("AppPlatformEmailMessageHeaders", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.SmsMessage", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Provider") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Provider"); + + b.Property("Reason") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Reason"); + + b.Property("Receiver") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Receiver"); + + b.Property("SendCount") + .HasColumnType("int"); + + b.Property("SendTime") + .HasColumnType("datetime(6)"); + + b.Property("Sender") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Sender"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformSmsMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Authors") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Authors"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Description"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("ForceUpdate") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Name"); + + b.Property("Note") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Note"); + + b.Property("Version") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Version"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Version"); + + b.ToTable("AppPlatformPackages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Authors") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Authors"); + + b.Property("ContentType") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("ContentType"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("License") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("License"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Name"); + + b.Property("PackageId") + .HasColumnType("char(36)"); + + b.Property("SHA256") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("SHA256"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("Summary") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)") + .HasColumnName("Summary"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)"); + + b.Property("Url") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("Url"); + + b.HasKey("Id"); + + b.HasIndex("PackageId", "Name"); + + b.ToTable("AppPlatformPackageBlobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Portal.Enterprise", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Address") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Address"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("EnglishName") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("EnglishName"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LegalMan") + .HasMaxLength(60) + .HasColumnType("varchar(60)") + .HasColumnName("LegalMan"); + + b.Property("Logo") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("Logo"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Name"); + + b.Property("OrganizationCode") + .HasMaxLength(16) + .HasColumnType("varchar(16)") + .HasColumnName("OrganizationCode"); + + b.Property("RegistrationCode") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("RegistrationCode"); + + b.Property("RegistrationDate") + .HasColumnType("datetime(6)"); + + b.Property("TaxCode") + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("TaxCode"); + + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformEnterprises", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("varchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasColumnType("longtext"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("varchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("char(36)") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorTenantName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("ImpersonatorTenantName"); + + b.Property("ImpersonatorUserId") + .HasColumnType("char(36)") + .HasColumnName("ImpersonatorUserId"); + + b.Property("ImpersonatorUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("ImpersonatorUserName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("TenantName"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("char(36)") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AuditLogId") + .HasColumnType("char(36)") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime(6)") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("varchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogExcelFile", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("FileName") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("FileName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuditLogExcelFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AuditLogId") + .HasColumnType("char(36)") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime(6)") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint unsigned") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("char(36)"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("EntityChangeId") + .HasColumnType("char(36)"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("tinyint(1)"); + + b.Property("IsVisibleToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatures", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpFeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("SourceTenantId") + .HasColumnType("char(36)"); + + b.Property("SourceUserId") + .HasColumnType("char(36)"); + + b.Property("TargetTenantId") + .HasColumnType("char(36)"); + + b.Property("TargetUserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique(); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("tinyint(1)") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("varchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("varchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("varchar(96)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.Property("LastAccessed") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("SignedIn") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("datetime(6)"); + + b.Property("LastSignInTime") + .HasColumnType("datetime(6)"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("varchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("tinyint(1)"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("datetime(6)"); + + b.Property("SourceUserId") + .HasColumnType("char(36)"); + + b.Property("StartTime") + .HasColumnType("datetime(6)"); + + b.Property("TargetUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("varchar(196)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("varbinary(1024)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("AbpUserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("varchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ClientSecret") + .HasColumnType("longtext"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ClientUri") + .HasColumnType("longtext"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("longtext"); + + b.Property("DisplayNames") + .HasColumnType("longtext"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("JsonWebKeySet") + .HasColumnType("longtext"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LogoUri") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("longtext"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("RedirectUris") + .HasColumnType("longtext"); + + b.Property("Requirements") + .HasColumnType("longtext"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("OpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApplicationId") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("Scopes") + .HasColumnType("longtext"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Scopes.OpenIddictScope", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Descriptions") + .HasColumnType("longtext"); + + b.Property("DisplayName") + .HasColumnType("longtext"); + + b.Property("DisplayNames") + .HasColumnType("longtext"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("Resources") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("OpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApplicationId") + .HasColumnType("char(36)"); + + b.Property("AuthorizationId") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Payload") + .HasColumnType("longtext"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("RedemptionDate") + .HasColumnType("datetime(6)"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("Type") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("ManagementPermissionName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint unsigned"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ResourceName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("ResourceName", "Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.ResourcePermissionGrant", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ResourceKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ResourceName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpResourcePermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("tinyint(1)"); + + b.Property("IsInherited") + .HasColumnType("tinyint(1)"); + + b.Property("IsVisibleToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.HasOne("LINGYUN.Abp.BlobManagement.BlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LINGYUN.Abp.BlobManagement.Blob", null) + .WithMany("Blobs") + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", "PropertyInfo") + .WithMany("Enums") + .HasForeignKey("PropertyInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PropertyInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "TypeInfo") + .WithMany("Properties") + .HasForeignKey("TypeInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.HasOne("LINGYUN.Abp.Demo.Authors.Author", null) + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.HasOne("LINGYUN.Abp.Demo.Books.Book", "Entity") + .WithMany() + .HasForeignKey("EntityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Entity"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null) + .WithMany("Infos") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition") + .WithMany() + .HasForeignKey("EditionId"); + + b.Navigation("Edition"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.HasOne("LINGYUN.Abp.Saas.Tenants.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", b => + { + b.HasOne("LINGYUN.Abp.WebhooksManagement.WebhookEventRecord", "WebhookEvent") + .WithOne() + .HasForeignKey("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", "WebhookEventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WebhookEvent"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.DataItem", b => + { + b.HasOne("LINGYUN.Platform.Datas.Data", null) + .WithMany("Items") + .HasForeignKey("DataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b => + { + b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null) + .WithMany("Attachments") + .HasForeignKey("FeedbackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b => + { + b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null) + .WithMany("Comments") + .HasForeignKey("FeedbackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageAttachment", b => + { + b.HasOne("LINGYUN.Platform.Messages.EmailMessage", null) + .WithMany("Attachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageHeader", b => + { + b.HasOne("LINGYUN.Platform.Messages.EmailMessage", null) + .WithMany("Headers") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => + { + b.HasOne("LINGYUN.Platform.Packages.Package", "Package") + .WithMany("Blobs") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("AbpUserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("json"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + + b.HasOne("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", null) + .WithMany() + .HasForeignKey("AuthorizationId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.Navigation("Blobs"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Navigation("Enums"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Navigation("Infos"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.Data", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b => + { + b.Navigation("Attachments"); + + b.Navigation("Comments"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessage", b => + { + b.Navigation("Attachments"); + + b.Navigation("Headers"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => + { + b.Navigation("Blobs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.cs new file mode 100644 index 000000000..923b820aa --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20260529063257_Add-Identity-User-Inactive.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations +{ + /// + public partial class AddIdentityUserInactive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpUserInactives", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + UserId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + LastSignInTime = table.Column(type: "datetime(6)", nullable: false), + LastNotificationTime = table.Column(type: "datetime(6)", nullable: true), + Status = table.Column(type: "int", nullable: false), + DeactivatedTime = table.Column(type: "datetime(6)", nullable: true), + CreationTime = table.Column(type: "datetime(6)", nullable: false), + CreatorId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserInactives", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserInactives_TenantId_UserId", + table: "AbpUserInactives", + columns: new[] { "TenantId", "UserId" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpUserInactives"); + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs index 484c1f628..0d7e68c28 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs @@ -1082,6 +1082,48 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio b.ToTable("AbpGdprRequests", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("datetime(6)"); + + b.Property("LastNotificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastSignInTime") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => { b.Property("Id") diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.Designer.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.Designer.cs new file mode 100644 index 000000000..bb44009f8 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.Designer.cs @@ -0,0 +1,6179 @@ +// +using System; +using LY.MicroService.Applications.Single.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Migrations +{ + [DbContext(typeof(SingleMigrationsDbContext))] + [Migration("20260530055941_Add-Identity-User-Inactive")] + partial class AddIdentityUserInactive + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql) + .HasAnnotation("ProductVersion", "10.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExpiredAt") + .HasColumnType("timestamp without time zone"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UpdateAt") + .HasColumnType("timestamp without time zone"); + + b.Property("Workspace") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.ToTable("AbpAIConversations", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ConversationId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ReplyAt") + .HasColumnType("timestamp without time zone"); + + b.Property("ReplyMessage") + .HasColumnType("text"); + + b.Property("Role") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Workspace") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ConversationId"); + + b.ToTable("AbpAITextChatMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CachedInputTokenCount") + .HasColumnType("bigint"); + + b.Property("ConversationId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("InputTokenCount") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("OutputTokenCount") + .HasColumnType("bigint"); + + b.Property("ReasoningTokenCount") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TotalTokenCount") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ConversationId"); + + b.ToTable("AbpAITokenUsages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tools.AIToolDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsGlobal") + .HasColumnType("boolean"); + + b.Property("IsSystem") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpAIAIToolDefinitionRecords", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiBaseUrl") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ApiKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FrequencyPenalty") + .HasColumnType("real"); + + b.Property("Instructions") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("IsSystem") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MaxOutputTokens") + .HasColumnType("integer"); + + b.Property("ModelName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("PresencePenalty") + .HasColumnType("real"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SystemPrompt") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Temperature") + .HasColumnType("real"); + + b.Property("Tools") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpAIWorkspaceDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uuid"); + + b.Property("ContentType") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("bigint"); + + b.Property("ExpirationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("ParentId"); + + b.HasIndex("TenantId", "ContainerId", "FullName"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.BlobContainer", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("PropertyInfoId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("PropertyInfoId", "Name"); + + b.ToTable("AbpAuthEntityEnums", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("JavaScriptType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("JavaScriptType"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("text"); + + b.Property("EntityTypeId") + .HasColumnType("uuid"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("text") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("integer"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("text"); + + b.Property("EntityTypeId") + .HasColumnType("uuid"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("text") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("integer"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.SubjectStrategy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Strategy") + .HasColumnType("integer"); + + b.Property("SubjectId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("SubjectId"); + + b.Property("SubjectName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("SubjectName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuthSubjectStrategys", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Authors.Author", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BirthDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ShortBio") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Demo_Authors", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Price") + .HasColumnType("real"); + + b.Property("PublishDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Demo_Books", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EntityId") + .HasMaxLength(64) + .HasColumnType("uuid") + .HasColumnName("EntityId"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("EntityType"); + + b.Property("OrganizationUnit") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("OrganizationUnit"); + + b.Property("Role") + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("Role"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("EntityId"); + + b.HasIndex("OrganizationUnit"); + + b.HasIndex("Role"); + + b.ToTable("Demo_BooksAuths", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text") + .HasColumnName("Data"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Provider"); + + b.Property("RequestId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RequestId"); + + b.ToTable("AbpGdprInfos", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("ReadyTime") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpGdprRequests", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastNotificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("CultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TwoLetterISOLanguageName") + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("TwoLetterISOLanguageName"); + + b.Property("UiCultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("UiCultureName"); + + b.HasKey("Id"); + + b.HasIndex("CultureName"); + + b.ToTable("AbpLocalizationLanguages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Resource", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DefaultCultureName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("DefaultCultureName"); + + b.Property("Description") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpLocalizationResources", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Text", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("CultureName"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("Key"); + + b.Property("ResourceName") + .HasColumnType("text"); + + b.Property("Value") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("AbpLocalizationTexts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Age") + .HasColumnType("integer"); + + b.Property("AvatarUrl") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Birthday") + .HasColumnType("timestamp without time zone"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastOnlineTime") + .HasColumnType("timestamp without time zone"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Sex") + .HasColumnType("integer"); + + b.Property("Sign") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatFriend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Black") + .HasColumnType("boolean"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("DontDisturb") + .HasColumnType("boolean"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FrientId") + .HasColumnType("uuid"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("RemarkName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SpecialFocus") + .HasColumnType("boolean"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "FrientId"); + + b.ToTable("AppUserChatFriends", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllowAddFriend") + .HasColumnType("boolean"); + + b.Property("AllowAnonymous") + .HasColumnType("boolean"); + + b.Property("AllowReceiveMessage") + .HasColumnType("boolean"); + + b.Property("AllowSendMessage") + .HasColumnType("boolean"); + + b.Property("RequireAddFriendValition") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("character varying(1048576)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("uuid"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("State") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("AdminUserId") + .HasColumnType("uuid"); + + b.Property("AllowAnonymous") + .HasColumnType("boolean"); + + b.Property("AllowSendMessage") + .HasColumnType("boolean"); + + b.Property("AvatarUrl") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MaxUserCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Notice") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Tag") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("character varying(1048576)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("State") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserGroupCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SilenceEnd") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserGroupCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ContentType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("ExpirationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("NotificationTypeName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Severity") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName"); + + b.ToTable("AppNotifications", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionGroupRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AllowSubscriptionToClients") + .HasColumnType("boolean"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.ToTable("AppNotificationDefinitionGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AllowSubscriptionToClients") + .HasColumnType("boolean"); + + b.Property("ContentType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("NotificationLifetime") + .HasColumnType("integer"); + + b.Property("NotificationType") + .HasColumnType("integer"); + + b.Property("Providers") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Template") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.ToTable("AppNotificationDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Reason") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SendTime") + .HasColumnType("timestamp without time zone"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName") + .HasDatabaseName("IX_Tenant_Send_Notification_Name"); + + b.ToTable("AppNotificationSendRecords", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("ReadStatus") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationId") + .HasDatabaseName("IX_Tenant_User_Notification_Id"); + + b.ToTable("AppUserNotifications", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.UserSubscribe", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationName") + .IsUnique() + .HasDatabaseName("IX_Tenant_User_Notification_Name"); + + b.ToTable("AppUserSubscribes", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Editions.Edition", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.ToTable("AbpEditions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisableTime") + .HasColumnType("timestamp without time zone"); + + b.Property("EditionId") + .HasColumnType("uuid"); + + b.Property("EnableTime") + .HasColumnType("timestamp without time zone"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("NormalizedName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.HasKey("Id"); + + b.HasIndex("EditionId"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpTenants", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobAction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("JobId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("JobId"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Name"); + + b.Property("Paramters") + .HasColumnType("text") + .HasColumnName("Paramters"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("TK_BackgroundJobActions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobInfo", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Args") + .HasColumnType("text") + .HasColumnName("Args"); + + b.Property("BeginTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Cron") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("Cron"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Description"); + + b.Property("EndTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Group") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Group"); + + b.Property("Interval") + .HasColumnType("integer"); + + b.Property("IsAbandoned") + .HasColumnType("boolean"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("JobType") + .HasColumnType("integer"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastRunTime") + .HasColumnType("timestamp without time zone"); + + b.Property("LockTimeOut") + .HasColumnType("integer"); + + b.Property("MaxCount") + .HasColumnType("integer"); + + b.Property("MaxTryCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Name"); + + b.Property("NextRunTime") + .HasColumnType("timestamp without time zone"); + + b.Property("NodeName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("NodeName"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("Result") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)") + .HasColumnName("Result"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TriggerCount") + .HasColumnType("integer"); + + b.Property("TryCount") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)") + .HasColumnName("Type"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Group"); + + b.ToTable("TK_BackgroundJobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Exception") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)") + .HasColumnName("Exception"); + + b.Property("JobGroup") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("JobGroup"); + + b.Property("JobId") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("JobId"); + + b.Property("JobName") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("JobName"); + + b.Property("JobType") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)") + .HasColumnName("JobType"); + + b.Property("Message") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)") + .HasColumnName("Message"); + + b.Property("RunTime") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("JobGroup", "JobName"); + + b.ToTable("TK_BackgroundJobLogs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplate", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Content") + .HasMaxLength(1048576) + .HasColumnType("character varying(1048576)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Culture") + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("Culture"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("DisplayName"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .HasDatabaseName("IX_Tenant_Text_Template_Name"); + + b.ToTable("AbpTextTemplates", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplateDefinition", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultCultureName") + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("DefaultCultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsInlineLocalized") + .HasColumnType("boolean"); + + b.Property("IsLayout") + .HasColumnType("boolean"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("Layout") + .HasMaxLength(60) + .HasColumnType("character varying(60)") + .HasColumnName("Layout"); + + b.Property("LocalizationResourceName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("LocalizationResourceName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Name"); + + b.Property("RenderEngine") + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("RenderEngine"); + + b.HasKey("Id"); + + b.ToTable("AbpTextTemplateDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("RequiredFeatures") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpWebhooksWebhooks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookEventRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("Data") + .HasMaxLength(2147483647) + .HasColumnType("text") + .HasColumnName("Data"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("WebhookName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("WebhookName"); + + b.HasKey("Id"); + + b.ToTable("AbpWebhooksEvents", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpWebhooksWebhookGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("RequestHeaders") + .HasMaxLength(2147483647) + .HasColumnType("text") + .HasColumnName("RequestHeaders"); + + b.Property("Response") + .HasMaxLength(2147483647) + .HasColumnType("text") + .HasColumnName("Response"); + + b.Property("ResponseHeaders") + .HasMaxLength(2147483647) + .HasColumnType("text") + .HasColumnName("ResponseHeaders"); + + b.Property("ResponseStatusCode") + .HasColumnType("integer"); + + b.Property("SendExactSameData") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("WebhookEventId") + .HasColumnType("uuid"); + + b.Property("WebhookSubscriptionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("WebhookEventId"); + + b.ToTable("AbpWebhooksSendAttempts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Description"); + + b.Property("Headers") + .HasMaxLength(2147483647) + .HasColumnType("text") + .HasColumnName("Headers"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Secret") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Secret"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TimeoutDuration") + .HasColumnType("integer"); + + b.Property("WebhookUri") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("WebhookUri"); + + b.Property("Webhooks") + .HasMaxLength(2147483647) + .HasColumnType("text") + .HasColumnName("Webhooks"); + + b.HasKey("Id"); + + b.ToTable("AbpWebhooksSubscriptions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.Data", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("Name"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AppPlatformDatas", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.DataItem", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AllowBeNull") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DataId") + .HasColumnType("uuid"); + + b.Property("DefaultValue") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DefaultValue"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("Name"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DataId"); + + b.HasIndex("Name"); + + b.ToTable("AppPlatformDataItems", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Category"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformFeedbacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("FeedbackId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Url"); + + b.HasKey("Id"); + + b.HasIndex("FeedbackId"); + + b.ToTable("AppPlatformFeedbackAttachments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Capacity") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Capacity"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("FeedbackId") + .HasColumnType("uuid"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("FeedbackId"); + + b.ToTable("AppPlatformFeedbackComments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DataId") + .HasColumnType("uuid"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Framework"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("Path") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Path"); + + b.Property("Redirect") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Redirect"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformLayouts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.Menu", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(23) + .HasColumnType("character varying(23)") + .HasColumnName("Code"); + + b.Property("Component") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Component"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Framework"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsPublic") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LayoutId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("Path") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Path"); + + b.Property("Redirect") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Redirect"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.RoleMenu", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("uuid"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("RoleName"); + + b.Property("Startup") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleName", "MenuId"); + + b.ToTable("AppPlatformRoleMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.UserFavoriteMenu", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AliasName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("AliasName"); + + b.Property("Color") + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("Color"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Framework"); + + b.Property("Icon") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("Icon"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Path"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "MenuId"); + + b.ToTable("AppPlatformUserFavoriteMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.UserMenu", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("uuid"); + + b.Property("Startup") + .HasColumnType("boolean"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "MenuId"); + + b.ToTable("AppPlatformUserMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BodyTransferEncoding") + .HasColumnType("integer"); + + b.Property("CC") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("CC"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeliveryNotificationOptions") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("From") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("From"); + + b.Property("IsBodyHtml") + .HasColumnType("boolean"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Normalize") + .HasColumnType("boolean"); + + b.Property("Priority") + .HasColumnType("integer"); + + b.Property("Provider") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Provider"); + + b.Property("Reason") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Reason"); + + b.Property("Receiver") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Receiver"); + + b.Property("SendCount") + .HasColumnType("integer"); + + b.Property("SendTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Sender") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Sender"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("Subject") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Subject"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformEmailMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("BlobName"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Name"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("AppPlatformEmailMessageAttachments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Key") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Key"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("AppPlatformEmailMessageHeaders", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.SmsMessage", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Provider") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("Provider"); + + b.Property("Reason") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Reason"); + + b.Property("Receiver") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Receiver"); + + b.Property("SendCount") + .HasColumnType("integer"); + + b.Property("SendTime") + .HasColumnType("timestamp without time zone"); + + b.Property("Sender") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Sender"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformSmsMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Authors") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Authors"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Description"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("ForceUpdate") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Name"); + + b.Property("Note") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Note"); + + b.Property("Version") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("Version"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Version"); + + b.ToTable("AppPlatformPackages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Authors") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("Authors"); + + b.Property("ContentType") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ContentType"); + + b.Property("CreatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("License") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("License"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Name"); + + b.Property("PackageId") + .HasColumnType("uuid"); + + b.Property("SHA256") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("SHA256"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("Summary") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)") + .HasColumnName("Summary"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp without time zone"); + + b.Property("Url") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("Url"); + + b.HasKey("Id"); + + b.HasIndex("PackageId", "Name"); + + b.ToTable("AppPlatformPackageBlobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Portal.Enterprise", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Address") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Address"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("EnglishName") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("EnglishName"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LegalMan") + .HasMaxLength(60) + .HasColumnType("character varying(60)") + .HasColumnName("LegalMan"); + + b.Property("Logo") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("Logo"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Name"); + + b.Property("OrganizationCode") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("OrganizationCode"); + + b.Property("RegistrationCode") + .HasMaxLength(30) + .HasColumnType("character varying(30)") + .HasColumnName("RegistrationCode"); + + b.Property("RegistrationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("TaxCode") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("TaxCode"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformEnterprises", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasColumnType("text"); + + b.Property("ExecutionDuration") + .HasColumnType("integer") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("integer") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uuid") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorTenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("ImpersonatorTenantName"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uuid") + .HasColumnName("ImpersonatorUserId"); + + b.Property("ImpersonatorUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ImpersonatorUserName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("TenantName"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AuditLogId") + .HasColumnType("uuid") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("integer") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogExcelFile", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("FileName") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("FileName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuditLogExcelFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AuditLogId") + .HasColumnType("uuid") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("smallint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uuid"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EntityChangeId") + .HasColumnType("uuid"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("boolean"); + + b.Property("IsVisibleToClients") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatures", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpFeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Required") + .HasColumnType("boolean"); + + b.Property("ValueType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("SourceTenantId") + .HasColumnType("uuid"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("TargetTenantId") + .HasColumnType("uuid"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique(); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("boolean") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("boolean") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("character varying(96)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("LastAccessed") + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("SignedIn") + .HasColumnType("timestamp without time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("boolean"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EndTime") + .HasColumnType("timestamp without time zone"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("timestamp without time zone"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("character varying(196)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("bytea"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("AbpUserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("character varying(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("integer"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ClientSecret") + .HasColumnType("text"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ClientUri") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("DisplayNames") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("text"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("JsonWebKeySet") + .HasColumnType("text"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("LogoUri") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("text"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("RedirectUris") + .HasColumnType("text"); + + b.Property("Requirements") + .HasColumnType("text"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("OpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("Scopes") + .HasColumnType("text"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Scopes.OpenIddictScope", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uuid") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Descriptions") + .HasColumnType("text"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("DisplayNames") + .HasColumnType("text"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uuid") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("Resources") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("OpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("AuthorizationId") + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("RedemptionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("Type") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("IsEnabled") + .HasColumnType("boolean"); + + b.Property("ManagementPermissionName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("MultiTenancySide") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ResourceName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("ResourceName", "Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.ResourcePermissionGrant", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ResourceKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ResourceName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpResourcePermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExtraProperties") + .HasColumnType("text") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("boolean"); + + b.Property("IsInherited") + .HasColumnType("boolean"); + + b.Property("IsVisibleToClients") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.HasOne("LINGYUN.Abp.BlobManagement.BlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LINGYUN.Abp.BlobManagement.Blob", null) + .WithMany("Blobs") + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", "PropertyInfo") + .WithMany("Enums") + .HasForeignKey("PropertyInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PropertyInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "TypeInfo") + .WithMany("Properties") + .HasForeignKey("TypeInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.HasOne("LINGYUN.Abp.Demo.Authors.Author", null) + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.HasOne("LINGYUN.Abp.Demo.Books.Book", "Entity") + .WithMany() + .HasForeignKey("EntityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Entity"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null) + .WithMany("Infos") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition") + .WithMany() + .HasForeignKey("EditionId"); + + b.Navigation("Edition"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.HasOne("LINGYUN.Abp.Saas.Tenants.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", b => + { + b.HasOne("LINGYUN.Abp.WebhooksManagement.WebhookEventRecord", "WebhookEvent") + .WithOne() + .HasForeignKey("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", "WebhookEventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WebhookEvent"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.DataItem", b => + { + b.HasOne("LINGYUN.Platform.Datas.Data", null) + .WithMany("Items") + .HasForeignKey("DataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b => + { + b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null) + .WithMany("Attachments") + .HasForeignKey("FeedbackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b => + { + b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null) + .WithMany("Comments") + .HasForeignKey("FeedbackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageAttachment", b => + { + b.HasOne("LINGYUN.Platform.Messages.EmailMessage", null) + .WithMany("Attachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageHeader", b => + { + b.HasOne("LINGYUN.Platform.Messages.EmailMessage", null) + .WithMany("Headers") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => + { + b.HasOne("LINGYUN.Platform.Packages.Package", "Package") + .WithMany("Blobs") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("AbpUserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("jsonb"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + + b.HasOne("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", null) + .WithMany() + .HasForeignKey("AuthorizationId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.Navigation("Blobs"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Navigation("Enums"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Navigation("Infos"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.Data", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b => + { + b.Navigation("Attachments"); + + b.Navigation("Comments"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessage", b => + { + b.Navigation("Attachments"); + + b.Navigation("Headers"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => + { + b.Navigation("Blobs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.cs new file mode 100644 index 000000000..b3608133c --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260530055941_Add-Identity-User-Inactive.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Migrations +{ + /// + public partial class AddIdentityUserInactive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpUserInactives", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: true), + LastSignInTime = table.Column(type: "timestamp with time zone", nullable: false), + LastNotificationTime = table.Column(type: "timestamp with time zone", nullable: true), + Status = table.Column(type: "integer", nullable: false), + DeactivatedTime = table.Column(type: "timestamp with time zone", nullable: true), + CreationTime = table.Column(type: "timestamp without time zone", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserInactives", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserInactives_TenantId_UserId", + table: "AbpUserInactives", + columns: new[] { "TenantId", "UserId" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpUserInactives"); + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/SingleMigrationsDbContextModelSnapshot.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/SingleMigrationsDbContextModelSnapshot.cs index c925fb5f1..66cdc6cf0 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/SingleMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/SingleMigrationsDbContextModelSnapshot.cs @@ -1082,6 +1082,48 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Mig b.ToTable("AbpGdprRequests", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("timestamp without time zone") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uuid") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastNotificationTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSignInTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => { b.Property("Id") diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.Designer.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.Designer.cs new file mode 100644 index 000000000..fb954060e --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.Designer.cs @@ -0,0 +1,6186 @@ +// +using System; +using LY.MicroService.Applications.Single.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migrations +{ + [DbContext(typeof(SingleMigrationsDbContext))] + [Migration("20260530060009_Add-Identity-User-Inactive")] + partial class AddIdentityUserInactive + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "10.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExpiredAt") + .HasColumnType("datetime2"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UpdateAt") + .HasColumnType("datetime2"); + + b.Property("Workspace") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.ToTable("AbpAIConversations", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("ConversationId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ReplyAt") + .HasColumnType("datetime2"); + + b.Property("ReplyMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("Role") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Workspace") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ConversationId"); + + b.ToTable("AbpAITextChatMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CachedInputTokenCount") + .HasColumnType("bigint"); + + b.Property("ConversationId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("InputTokenCount") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MessageId") + .HasColumnType("uniqueidentifier"); + + b.Property("OutputTokenCount") + .HasColumnType("bigint"); + + b.Property("ReasoningTokenCount") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TotalTokenCount") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ConversationId"); + + b.ToTable("AbpAITokenUsages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tools.AIToolDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("IsGlobal") + .HasColumnType("bit"); + + b.Property("IsSystem") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpAIAIToolDefinitionRecords", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ApiBaseUrl") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ApiKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FrequencyPenalty") + .HasColumnType("real"); + + b.Property("Instructions") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("IsSystem") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MaxOutputTokens") + .HasColumnType("int"); + + b.Property("ModelName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("PresencePenalty") + .HasColumnType("real"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("SystemPrompt") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Temperature") + .HasColumnType("real"); + + b.Property("Tools") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpAIWorkspaceDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("ContentType") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("bigint"); + + b.Property("ExpirationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("ParentId"); + + b.HasIndex("TenantId", "ContainerId", "FullName"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.BlobContainer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("PropertyInfoId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("PropertyInfoId", "Name"); + + b.ToTable("AbpAuthEntityEnums", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("JavaScriptType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("JavaScriptType"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("nvarchar(max)"); + + b.Property("EntityTypeId") + .HasColumnType("uniqueidentifier"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("nvarchar(max)") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessedProperties") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("AccessedProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("nvarchar(max)"); + + b.Property("EntityTypeId") + .HasColumnType("uniqueidentifier"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("nvarchar(max)") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.SubjectStrategy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Strategy") + .HasColumnType("int"); + + b.Property("SubjectId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("SubjectId"); + + b.Property("SubjectName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("SubjectName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuthSubjectStrategys", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Authors.Author", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("BirthDate") + .HasColumnType("datetime2"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ShortBio") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("Demo_Authors", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Price") + .HasColumnType("real"); + + b.Property("PublishDate") + .HasColumnType("datetime2"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Demo_Books", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EntityId") + .HasMaxLength(64) + .HasColumnType("uniqueidentifier") + .HasColumnName("EntityId"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityType"); + + b.Property("OrganizationUnit") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)") + .HasColumnName("OrganizationUnit"); + + b.Property("Role") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)") + .HasColumnName("Role"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("EntityId"); + + b.HasIndex("OrganizationUnit"); + + b.HasIndex("Role"); + + b.ToTable("Demo_BooksAuths", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("Data"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Provider"); + + b.Property("RequestId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RequestId"); + + b.ToTable("AbpGdprInfos", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("ReadyTime") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpGdprRequests", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("LastNotificationTime") + .HasColumnType("datetimeoffset"); + + b.Property("LastSignInTime") + .HasColumnType("datetimeoffset"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)") + .HasColumnName("CultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("TwoLetterISOLanguageName") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("TwoLetterISOLanguageName"); + + b.Property("UiCultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)") + .HasColumnName("UiCultureName"); + + b.HasKey("Id"); + + b.HasIndex("CultureName"); + + b.ToTable("AbpLocalizationLanguages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Resource", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DefaultCultureName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("DefaultCultureName"); + + b.Property("Description") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("DisplayName"); + + b.Property("Enable") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpLocalizationResources", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Text", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CultureName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)") + .HasColumnName("CultureName"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("Key"); + + b.Property("ResourceName") + .HasColumnType("nvarchar(max)"); + + b.Property("Value") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("AbpLocalizationTexts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Age") + .HasColumnType("int"); + + b.Property("AvatarUrl") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Birthday") + .HasColumnType("datetime2"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LastOnlineTime") + .HasColumnType("datetime2"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Sex") + .HasColumnType("int"); + + b.Property("Sign") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatFriend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Black") + .HasColumnType("bit"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("DontDisturb") + .HasColumnType("bit"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FrientId") + .HasColumnType("uniqueidentifier"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("RemarkName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("SpecialFocus") + .HasColumnType("bit"); + + b.Property("Status") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "FrientId"); + + b.ToTable("AppUserChatFriends", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AllowAddFriend") + .HasColumnType("bit"); + + b.Property("AllowAnonymous") + .HasColumnType("bit"); + + b.Property("AllowReceiveMessage") + .HasColumnType("bit"); + + b.Property("AllowSendMessage") + .HasColumnType("bit"); + + b.Property("RequireAddFriendValition") + .HasColumnType("bit"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("AdminUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("AllowAnonymous") + .HasColumnType("bit"); + + b.Property("AllowSendMessage") + .HasColumnType("bit"); + + b.Property("AvatarUrl") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Notice") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Tag") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendUserName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserGroupCard", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsAdmin") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("NickName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("SilenceEnd") + .HasColumnType("datetime2"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserGroupCards", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ContentType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("ExpirationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("NotificationTypeName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Severity") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName"); + + b.ToTable("AppNotifications", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionGroupRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllowSubscriptionToClients") + .HasColumnType("bit"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("AppNotificationDefinitionGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllowSubscriptionToClients") + .HasColumnType("bit"); + + b.Property("ContentType") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("NotificationLifetime") + .HasColumnType("int"); + + b.Property("NotificationType") + .HasColumnType("int"); + + b.Property("Providers") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Template") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("AppNotificationDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Reason") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SendTime") + .HasColumnType("datetime2"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName") + .HasDatabaseName("IX_Tenant_Send_Notification_Name"); + + b.ToTable("AppNotificationSendRecords", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("ReadStatus") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationId") + .HasDatabaseName("IX_Tenant_User_Notification_Id"); + + b.ToTable("AppUserNotifications", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Notifications.UserSubscribe", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("NotificationName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationName") + .IsUnique() + .HasDatabaseName("IX_Tenant_User_Notification_Name") + .HasFilter("[TenantId] IS NOT NULL"); + + b.ToTable("AppUserSubscribes", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Editions.Edition", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.ToTable("AbpEditions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisableTime") + .HasColumnType("datetime2"); + + b.Property("EditionId") + .HasColumnType("uniqueidentifier"); + + b.Property("EnableTime") + .HasColumnType("datetime2"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("NormalizedName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("EditionId"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpTenants", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobAction", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("JobId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("JobId"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("Name"); + + b.Property("Paramters") + .HasColumnType("nvarchar(max)") + .HasColumnName("Paramters"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("TK_BackgroundJobActions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobInfo", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("Args") + .HasColumnType("nvarchar(max)") + .HasColumnName("Args"); + + b.Property("BeginTime") + .HasColumnType("datetime2"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Cron") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)") + .HasColumnName("Cron"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Description"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Group") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("Group"); + + b.Property("Interval") + .HasColumnType("int"); + + b.Property("IsAbandoned") + .HasColumnType("bit"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("JobType") + .HasColumnType("int"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LastRunTime") + .HasColumnType("datetime2"); + + b.Property("LockTimeOut") + .HasColumnType("int"); + + b.Property("MaxCount") + .HasColumnType("int"); + + b.Property("MaxTryCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("Name"); + + b.Property("NextRunTime") + .HasColumnType("datetime2"); + + b.Property("NodeName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("NodeName"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Result") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)") + .HasColumnName("Result"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TriggerCount") + .HasColumnType("int"); + + b.Property("TryCount") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)") + .HasColumnName("Type"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Group"); + + b.ToTable("TK_BackgroundJobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TaskManagement.BackgroundJobLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Exception") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Exception"); + + b.Property("JobGroup") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("JobGroup"); + + b.Property("JobId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("JobId"); + + b.Property("JobName") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("JobName"); + + b.Property("JobType") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)") + .HasColumnName("JobType"); + + b.Property("Message") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)") + .HasColumnName("Message"); + + b.Property("RunTime") + .HasColumnType("datetime2"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("JobGroup", "JobName"); + + b.ToTable("TK_BackgroundJobLogs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplate", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(1048576) + .HasColumnType("nvarchar(max)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Culture") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("Culture"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("DisplayName"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("Name"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .HasDatabaseName("IX_Tenant_Text_Template_Name"); + + b.ToTable("AbpTextTemplates", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplateDefinition", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultCultureName") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("DefaultCultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsInlineLocalized") + .HasColumnType("bit"); + + b.Property("IsLayout") + .HasColumnType("bit"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Layout") + .HasMaxLength(60) + .HasColumnType("nvarchar(60)") + .HasColumnName("Layout"); + + b.Property("LocalizationResourceName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("LocalizationResourceName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Name"); + + b.Property("RenderEngine") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("RenderEngine"); + + b.HasKey("Id"); + + b.ToTable("AbpTextTemplateDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("RequiredFeatures") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpWebhooksWebhooks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookEventRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("Data") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)") + .HasColumnName("Data"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("WebhookName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("WebhookName"); + + b.HasKey("Id"); + + b.ToTable("AbpWebhooksEvents", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpWebhooksWebhookGroups", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("RequestHeaders") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)") + .HasColumnName("RequestHeaders"); + + b.Property("Response") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)") + .HasColumnName("Response"); + + b.Property("ResponseHeaders") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)") + .HasColumnName("ResponseHeaders"); + + b.Property("ResponseStatusCode") + .HasColumnType("int"); + + b.Property("SendExactSameData") + .HasColumnType("bit"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("WebhookEventId") + .HasColumnType("uniqueidentifier"); + + b.Property("WebhookSubscriptionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("WebhookEventId"); + + b.ToTable("AbpWebhooksSendAttempts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Description"); + + b.Property("Headers") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)") + .HasColumnName("Headers"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Secret") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Secret"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TimeoutDuration") + .HasColumnType("int"); + + b.Property("WebhookUri") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("WebhookUri"); + + b.Property("Webhooks") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)") + .HasColumnName("Webhooks"); + + b.HasKey("Id"); + + b.ToTable("AbpWebhooksSubscriptions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.Data", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("Name"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AppPlatformDatas", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.DataItem", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllowBeNull") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(true); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DataId") + .HasColumnType("uniqueidentifier"); + + b.Property("DefaultValue") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DefaultValue"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Description"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("Name"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("DataId"); + + b.HasIndex("Name"); + + b.ToTable("AppPlatformDataItems", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Category"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformFeedbacks", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("FeedbackId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Url"); + + b.HasKey("Id"); + + b.HasIndex("FeedbackId"); + + b.ToTable("AppPlatformFeedbackAttachments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Capacity") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Capacity"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("FeedbackId") + .HasColumnType("uniqueidentifier"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("FeedbackId"); + + b.ToTable("AppPlatformFeedbackComments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Layouts.Layout", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DataId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Framework"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("Path") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Path"); + + b.Property("Redirect") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Redirect"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformLayouts", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.Menu", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(23) + .HasColumnType("nvarchar(23)") + .HasColumnName("Code"); + + b.Property("Component") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Component"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Framework"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsPublic") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LayoutId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Path") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Path"); + + b.Property("Redirect") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Redirect"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.RoleMenu", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("RoleName"); + + b.Property("Startup") + .HasColumnType("bit"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleName", "MenuId"); + + b.ToTable("AppPlatformRoleMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.UserFavoriteMenu", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AliasName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("AliasName"); + + b.Property("Color") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("Color"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Framework") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Framework"); + + b.Property("Icon") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("Icon"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Path"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "MenuId"); + + b.ToTable("AppPlatformUserFavoriteMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Menus.UserMenu", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MenuId") + .HasColumnType("uniqueidentifier"); + + b.Property("Startup") + .HasColumnType("bit"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "MenuId"); + + b.ToTable("AppPlatformUserMenus", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessage", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("BodyTransferEncoding") + .HasColumnType("int"); + + b.Property("CC") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("CC"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeliveryNotificationOptions") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("From") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("From"); + + b.Property("IsBodyHtml") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Normalize") + .HasColumnType("bit"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Provider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Provider"); + + b.Property("Reason") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Reason"); + + b.Property("Receiver") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Receiver"); + + b.Property("SendCount") + .HasColumnType("int"); + + b.Property("SendTime") + .HasColumnType("datetime2"); + + b.Property("Sender") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Sender"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Subject") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Subject"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformEmailMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageAttachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BlobName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("BlobName"); + + b.Property("MessageId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Name"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("AppPlatformEmailMessageAttachments", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Key") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Key"); + + b.Property("MessageId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Value"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("AppPlatformEmailMessageHeaders", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.SmsMessage", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Provider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("Provider"); + + b.Property("Reason") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Reason"); + + b.Property("Receiver") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Receiver"); + + b.Property("SendCount") + .HasColumnType("int"); + + b.Property("SendTime") + .HasColumnType("datetime2"); + + b.Property("Sender") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Sender"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformSmsMessages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Authors") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("Authors"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Description"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("ForceUpdate") + .HasColumnType("bit"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Name"); + + b.Property("Note") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Note"); + + b.Property("Version") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("Version"); + + b.HasKey("Id"); + + b.HasIndex("Name", "Version"); + + b.ToTable("AppPlatformPackages", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Authors") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)") + .HasColumnName("Authors"); + + b.Property("ContentType") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ContentType"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DownloadCount") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("License") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("License"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Name"); + + b.Property("PackageId") + .HasColumnType("uniqueidentifier"); + + b.Property("SHA256") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SHA256"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("Summary") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)") + .HasColumnName("Summary"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.Property("Url") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("Url"); + + b.HasKey("Id"); + + b.HasIndex("PackageId", "Name"); + + b.ToTable("AppPlatformPackageBlobs", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Platform.Portal.Enterprise", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Address") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Address"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EnglishName") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("EnglishName"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LegalMan") + .HasMaxLength(60) + .HasColumnType("nvarchar(60)") + .HasColumnName("LegalMan"); + + b.Property("Logo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("Logo"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Name"); + + b.Property("OrganizationCode") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("OrganizationCode"); + + b.Property("RegistrationCode") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)") + .HasColumnName("RegistrationCode"); + + b.Property("RegistrationDate") + .HasColumnType("datetime2"); + + b.Property("TaxCode") + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("TaxCode"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.ToTable("AppPlatformEnterprises", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasColumnType("nvarchar(max)"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorTenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ImpersonatorTenantName"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorUserId"); + + b.Property("ImpersonatorUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ImpersonatorUserName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("TenantName"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogExcelFile", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("FileName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("FileName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpAuditLogExcelFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime2") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("bit"); + + b.Property("IsVisibleToClients") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatures", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + b.ToTable("AbpFeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SignedIn") + .HasColumnType("datetime2"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("bit") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + + b.Property("LastSignInTime") + .HasColumnType("datetimeoffset"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("varbinary(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("CreatedAt") + .HasColumnType("datetimeoffset"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("AbpUserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ClientSecret") + .HasColumnType("nvarchar(max)"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("ClientUri") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("JsonWebKeySet") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LogoUri") + .HasColumnType("nvarchar(max)"); + + b.Property("Permissions") + .HasColumnType("nvarchar(max)"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedirectUris") + .HasColumnType("nvarchar(max)"); + + b.Property("Requirements") + .HasColumnType("nvarchar(max)"); + + b.Property("Settings") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("OpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Scopes") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Scopes.OpenIddictScope", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Descriptions") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("DisplayNames") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Resources") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("OpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationId") + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorizationId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Payload") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedemptionDate") + .HasColumnType("datetime2"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("ManagementPermissionName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ResourceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("ResourceName", "Name") + .IsUnique() + .HasFilter("[ResourceName] IS NOT NULL"); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[TenantId] IS NOT NULL"); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.ResourcePermissionGrant", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ResourceKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ResourceName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ResourceName", "ResourceKey", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[TenantId] IS NOT NULL"); + + b.ToTable("AbpResourcePermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("bit"); + + b.Property("IsInherited") + .HasColumnType("bit"); + + b.Property("IsVisibleToClients") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.HasOne("LINGYUN.Abp.BlobManagement.BlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LINGYUN.Abp.BlobManagement.Blob", null) + .WithMany("Blobs") + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", "PropertyInfo") + .WithMany("Enums") + .HasForeignKey("PropertyInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PropertyInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "TypeInfo") + .WithMany("Properties") + .HasForeignKey("TypeInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b => + { + b.HasOne("LINGYUN.Abp.Demo.Authors.Author", null) + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b => + { + b.HasOne("LINGYUN.Abp.Demo.Books.Book", "Entity") + .WithMany() + .HasForeignKey("EntityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Entity"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null) + .WithMany("Infos") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition") + .WithMany() + .HasForeignKey("EditionId"); + + b.Navigation("Edition"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.HasOne("LINGYUN.Abp.Saas.Tenants.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", b => + { + b.HasOne("LINGYUN.Abp.WebhooksManagement.WebhookEventRecord", "WebhookEvent") + .WithOne() + .HasForeignKey("LINGYUN.Abp.WebhooksManagement.WebhookSendRecord", "WebhookEventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("WebhookEvent"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.DataItem", b => + { + b.HasOne("LINGYUN.Platform.Datas.Data", null) + .WithMany("Items") + .HasForeignKey("DataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackAttachment", b => + { + b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null) + .WithMany("Attachments") + .HasForeignKey("FeedbackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.FeedbackComment", b => + { + b.HasOne("LINGYUN.Platform.Feedbacks.Feedback", null) + .WithMany("Comments") + .HasForeignKey("FeedbackId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageAttachment", b => + { + b.HasOne("LINGYUN.Platform.Messages.EmailMessage", null) + .WithMany("Attachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessageHeader", b => + { + b.HasOne("LINGYUN.Platform.Messages.EmailMessage", null) + .WithMany("Headers") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.PackageBlob", b => + { + b.HasOne("LINGYUN.Platform.Packages.Package", "Package") + .WithMany("Blobs") + .HasForeignKey("PackageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Package"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("AbpUserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("nvarchar(max)"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + + b.HasOne("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", null) + .WithMany() + .HasForeignKey("AuthorizationId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.BlobManagement.Blob", b => + { + b.Navigation("Blobs"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Navigation("Enums"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Navigation("Infos"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Datas.Data", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Feedbacks.Feedback", b => + { + b.Navigation("Attachments"); + + b.Navigation("Comments"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Messages.EmailMessage", b => + { + b.Navigation("Attachments"); + + b.Navigation("Headers"); + }); + + modelBuilder.Entity("LINGYUN.Platform.Packages.Package", b => + { + b.Navigation("Blobs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.cs new file mode 100644 index 000000000..9a6978c53 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260530060009_Add-Identity-User-Inactive.cs @@ -0,0 +1,47 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migrations +{ + /// + public partial class AddIdentityUserInactive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpUserInactives", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + LastSignInTime = table.Column(type: "datetimeoffset", nullable: false), + LastNotificationTime = table.Column(type: "datetimeoffset", nullable: true), + Status = table.Column(type: "int", nullable: false), + DeactivatedTime = table.Column(type: "datetimeoffset", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserInactives", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserInactives_TenantId_UserId", + table: "AbpUserInactives", + columns: new[] { "TenantId", "UserId" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpUserInactives"); + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/SingleMigrationsDbContextModelSnapshot.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/SingleMigrationsDbContextModelSnapshot.cs index c21ead038..efa318d98 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/SingleMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/SingleMigrationsDbContextModelSnapshot.cs @@ -1082,6 +1082,48 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migr b.ToTable("AbpGdprRequests", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("datetimeoffset"); + + b.Property("LastNotificationTime") + .HasColumnType("datetimeoffset"); + + b.Property("LastSignInTime") + .HasColumnType("datetimeoffset"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => { b.Property("Id") diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs index c9616a840..cd95d2b7a 100644 --- a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs +++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs @@ -12,6 +12,7 @@ using LINGYUN.Abp.Demo.Books; using LINGYUN.Abp.Demo.EntityFrameworkCore; using LINGYUN.Abp.Gdpr; using LINGYUN.Abp.Gdpr.EntityFrameworkCore; +using LINGYUN.Abp.Identity.EntityFrameworkCore; using LINGYUN.Abp.LocalizationManagement; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.MessageService.Chat; @@ -39,7 +40,6 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.AuditLogging; using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.FeatureManagement; using Volo.Abp.FeatureManagement.EntityFrameworkCore; @@ -285,5 +285,7 @@ public class SingleMigrationsDbContext : modelBuilder.ConfigureAIManagement(); modelBuilder.ConfigureBlobManagement(); + + modelBuilder.ConfigureIdentityUserInactive(); } } diff --git a/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs b/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs index abbd5af5a..fcaec835c 100644 --- a/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs +++ b/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Gdpr.EntityFrameworkCore; +using LINGYUN.Abp.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -24,5 +25,7 @@ public class AuthServerMigrationsDbContext : AbpDbContext +using System; +using LY.MicroService.AuthServer.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.AuthServer.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(AuthServerMigrationsDbContext))] + [Migration("20260530061141_Add-Identity-User-Inactive")] + partial class AddIdentityUserInactive + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "10.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Data"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Provider"); + + b.Property("RequestId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("RequestId"); + + b.ToTable("AbpGdprInfos", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("ReadyTime") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpGdprRequests", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("datetime(6)"); + + b.Property("LastNotificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastSignInTime") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("SourceTenantId") + .HasColumnType("char(36)"); + + b.Property("SourceUserId") + .HasColumnType("char(36)"); + + b.Property("TargetTenantId") + .HasColumnType("char(36)"); + + b.Property("TargetUserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique(); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("tinyint(1)") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("tinyint(1)") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("varchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("varchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("varchar(96)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.Property("LastAccessed") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("SignedIn") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("datetime(6)"); + + b.Property("LastSignInTime") + .HasColumnType("datetime(6)"); + + b.Property("Leaved") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("Leaved"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("varchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("tinyint(1)"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EndTime") + .HasColumnType("datetime(6)"); + + b.Property("SourceUserId") + .HasColumnType("char(36)"); + + b.Property("StartTime") + .HasColumnType("datetime(6)"); + + b.Property("TargetUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("varchar(196)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.Property("CredentialId") + .HasMaxLength(1024) + .HasColumnType("varbinary(1024)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CredentialId"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserPasskeys", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "Password"); + + b.ToTable("AbpUserPasswordHistories", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("varchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ClientSecret") + .HasColumnType("longtext"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ClientUri") + .HasColumnType("longtext"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .HasColumnType("longtext"); + + b.Property("DisplayNames") + .HasColumnType("longtext"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("JsonWebKeySet") + .HasColumnType("longtext"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("LogoUri") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("longtext"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("RedirectUris") + .HasColumnType("longtext"); + + b.Property("Requirements") + .HasColumnType("longtext"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("OpenIddictApplications", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApplicationId") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("Scopes") + .HasColumnType("longtext"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Scopes.OpenIddictScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Descriptions") + .HasColumnType("longtext"); + + b.Property("DisplayName") + .HasColumnType("longtext"); + + b.Property("DisplayNames") + .HasColumnType("longtext"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("Resources") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("OpenIddictScopes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ApplicationId") + .HasColumnType("char(36)"); + + b.Property("AuthorizationId") + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Payload") + .HasColumnType("longtext"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("RedemptionDate") + .HasColumnType("datetime(6)"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("Type") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b => + { + b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null) + .WithMany("Infos") + .HasForeignKey("RequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasskey", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Passkeys") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Volo.Abp.Identity.IdentityPasskeyData", "Data", b1 => + { + b1.Property("IdentityUserPasskeyCredentialId"); + + b1.Property("AttestationObject"); + + b1.Property("ClientDataJson"); + + b1.Property("CreatedAt"); + + b1.Property("IsBackedUp"); + + b1.Property("IsBackupEligible"); + + b1.Property("IsUserVerified"); + + b1.Property("Name"); + + b1.Property("PublicKey"); + + b1.Property("SignCount"); + + b1.PrimitiveCollection("Transports"); + + b1.HasKey("IdentityUserPasskeyCredentialId"); + + b1.ToTable("AbpUserPasskeys"); + + b1 + .ToJson("Data") + .HasColumnType("json"); + + b1.WithOwner() + .HasForeignKey("IdentityUserPasskeyCredentialId"); + }); + + b.Navigation("Data"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserPasswordHistory", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("PasswordHistories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + }); + + modelBuilder.Entity("Volo.Abp.OpenIddict.Tokens.OpenIddictToken", b => + { + b.HasOne("Volo.Abp.OpenIddict.Applications.OpenIddictApplication", null) + .WithMany() + .HasForeignKey("ApplicationId"); + + b.HasOne("Volo.Abp.OpenIddict.Authorizations.OpenIddictAuthorization", null) + .WithMany() + .HasForeignKey("AuthorizationId"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b => + { + b.Navigation("Infos"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Passkeys"); + + b.Navigation("PasswordHistories"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530061141_Add-Identity-User-Inactive.cs b/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530061141_Add-Identity-User-Inactive.cs new file mode 100644 index 000000000..8569306ba --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530061141_Add-Identity-User-Inactive.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.AuthServer.EntityFrameworkCore.Migrations +{ + /// + public partial class AddIdentityUserInactive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpUserInactives", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + UserId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + LastSignInTime = table.Column(type: "datetime(6)", nullable: false), + LastNotificationTime = table.Column(type: "datetime(6)", nullable: true), + Status = table.Column(type: "int", nullable: false), + DeactivatedTime = table.Column(type: "datetime(6)", nullable: true), + CreationTime = table.Column(type: "datetime(6)", nullable: false), + CreatorId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserInactives", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserInactives_TenantId_UserId", + table: "AbpUserInactives", + columns: new[] { "TenantId", "UserId" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpUserInactives"); + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs b/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs index bd355a55c..fa5ea93bf 100644 --- a/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/migrations/LY.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs @@ -86,6 +86,48 @@ namespace LY.MicroService.AuthServer.DbMigrator.Migrations b.ToTable("AbpGdprRequests", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.Identity.IdentityUserInactive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeactivatedTime") + .HasColumnType("datetime(6)"); + + b.Property("LastNotificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastSignInTime") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpUserInactives", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs index 5ed0e651f..9d8f6cdfd 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs @@ -33,6 +33,7 @@ public class AbpAccountApplicationModule : AbpModule Configure(options => { options.Applications["MVC"].Urls[AccountUrlNames.EmailConfirm] = "Account/EmailConfirm"; + options.Applications["MVC"].Urls[AccountUrlNames.UserLogin] = "Account/Login"; }); Configure(options => diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Security/LINGYUN/Abp/Account/Security/AccountUrlNames.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Security/LINGYUN/Abp/Account/Security/AccountUrlNames.cs index 28104f22a..953870a66 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Security/LINGYUN/Abp/Account/Security/AccountUrlNames.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Security/LINGYUN/Abp/Account/Security/AccountUrlNames.cs @@ -4,4 +4,5 @@ public static class AccountUrlNames { public const string EmailConfirm = "Abp.Account.EmailConfirm"; public const string EmailVerifyLogin = "Abp.Account.EmailVerifyLogin"; + public const string UserLogin = "Abp.Account.UserLogin"; } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/IdentityUserAppService.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/IdentityUserAppService.cs index 14c958877..4d9d66151 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/IdentityUserAppService.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Application/LINGYUN/Abp/Identity/IdentityUserAppService.cs @@ -105,6 +105,8 @@ public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppSe #endregion + #region Security + [Authorize(IdentityPermissions.Users.ResetPassword)] public async virtual Task ChangePasswordAsync(Guid id, IdentityUserSetPasswordInput input) { @@ -139,6 +141,10 @@ public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppSe await CurrentUnitOfWork.SaveChangesAsync(); } + #endregion + + #region Lock + [Authorize(Volo.Abp.Identity.IdentityPermissions.Users.Update)] public async virtual Task LockAsync(Guid id, int seconds) { @@ -162,6 +168,8 @@ public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppSe await CurrentUnitOfWork.SaveChangesAsync(); } + #endregion + protected async virtual Task GetUserAsync(Guid id) { await IdentityOptions.SetAsync(); diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/InactiveUserStatus.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/InactiveUserStatus.cs new file mode 100644 index 000000000..ee4fb1761 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/InactiveUserStatus.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.Identity; + +public enum InactiveUserStatus +{ + Notified = 1, + Deactivated = 2, +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json index a347c358e..5ed0b7b6c 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json @@ -68,6 +68,10 @@ "Description:Abp.Identity.Session.ConcurrentLoginStrategy": "There is a setting in the identity section to prevent concurrent login.", "DisplayName:Abp.Identity.Session.LogoutFromSameTypeDevicesLimit": "Same Type Devices Login Limit", "Description:Abp.Identity.Session.LogoutFromSameTypeDevicesLimit": "Limit the login times of devices of the same type. The sessions that exceed the limit will be deregistered.", + "DisplayName:Abp.Identity.Link.UserLoginUri": "User Login Uri", + "Description:Abp.Identity.Link.UserLoginUri": "Set up a user login link for redirecting external authenticated users.", + "DisplayName:Identity.Link": "Link", + "Description:Identity.Link": "Used for setting up external access links", "DisplayName:NewPhoneNumber": "New Phone Number", "DisplayName:SmsVerifyCode": "SMS verification code", "DisplayName:EmailVerifyCode": "Mail verification code", diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json index eddcfaa1b..f2b073d39 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json @@ -68,6 +68,10 @@ "Description:Abp.Identity.Session.ConcurrentLoginStrategy": "用户重复登录会话策略", "DisplayName:Abp.Identity.Session.LogoutFromSameTypeDevicesLimit": "允许相同类型设备登录次数", "Description:Abp.Identity.Session.LogoutFromSameTypeDevicesLimit": "限制相同类型设备登录次数,超出限制的会话将被注销.", + "DisplayName:Abp.Identity.Link.UserLoginUri": "用户登录链接", + "Description:Abp.Identity.Link.UserLoginUri": "设置用户登录链接,用于外部认证用户重定向.", + "DisplayName:Identity.Link": "链接", + "Description:Identity.Link": "用于设定外部接入链接", "DisplayName:NewPhoneNumber": "新手机号码", "DisplayName:SmsVerifyCode": "短信验证码", "DisplayName:EmailVerifyCode": "邮件验证码", diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs index bcc0d6dc7..3c764fd5d 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs @@ -81,6 +81,18 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider displayName: L("DisplayName:Abp.Identity.Session.LogoutFromSameTypeDevicesLimit"), description: L("Description:Abp.Identity.Session.LogoutFromSameTypeDevicesLimit"), isVisibleToClients: false) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName), + + new SettingDefinition( + name: IdentitySettingNames.Link.UserLoginUri, + defaultValue: "http://localhost:8080/Account/Login", + displayName: L("DisplayName:Abp.Identity.Link.UserLoginUri"), + description: L("Description:Abp.Identity.Link.UserLoginUri"), + isVisibleToClients: false) .WithProviders( DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingNames.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingNames.cs index ab47a2548..a8bd511fa 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingNames.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingNames.cs @@ -41,4 +41,13 @@ public static class IdentitySettingNames /// public const string LogoutFromSameTypeDevicesLimit = SessionPrefix + ".LogoutFromSameTypeDevicesLimit"; } + + public static class Link + { + private const string LinkPrefix = Prefix + ".Link"; + /// + /// 用户登录页(包含协议的登录地址串,用于发送用户登录邮件中的链接) + /// + public const string UserLoginUri = LinkPrefix + ".UserLoginUri"; + } } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs index 9f0c8a58b..7ed5c893e 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs @@ -15,6 +15,7 @@ namespace LINGYUN.Abp.Identity; [DependsOn( typeof(AbpIdentityDomainSharedModule), + typeof(AbpIdentitySessionModule), typeof(AbpDistributedLockingAbstractionsModule), typeof(Volo.Abp.Identity.AbpIdentityDomainModule))] public class AbpIdentityDomainModule : AbpModule diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserInactiveRepository.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserInactiveRepository.cs new file mode 100644 index 000000000..dff07624d --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserInactiveRepository.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Identity; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.Identity; + +public interface IIdentityUserInactiveRepository : IBasicRepository +{ + Task FindByUserIdAsync( + Guid userId, + CancellationToken cancellationToken = default); + + Task GetInactiveUserCountAsync( + DateTime threshold, + IEnumerable exceptUserIds = null, + CancellationToken cancellationToken = default); + + Task> GetInactiveUserListAsync( + DateTime threshold, + IEnumerable exceptUserIds = null, + string sorting = nameof(IdentityUser.LastSignInTime), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default); + + Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default); + + Task> GetListAsync( + ISpecification specification, + string sorting = nameof(IdentityUserInactive.CreationTime), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserRepository.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserRepository.cs index 25adb8f15..35bf82c92 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserRepository.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IIdentityUserRepository.cs @@ -59,7 +59,7 @@ public interface IIdentityUserRepository : Volo.Abp.Identity.IIdentityUserReposi List userIds, bool includeDetails = false, CancellationToken cancellationToken = default - ); + ); /// /// 获取用户所有的组织机构列表 /// diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityUserInactive.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityUserInactive.cs new file mode 100644 index 000000000..cd3dcede9 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityUserInactive.cs @@ -0,0 +1,48 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.Identity; + +public class IdentityUserInactive : CreationAuditedEntity, IMultiTenant +{ + public virtual Guid UserId { get; protected set; } + + public virtual Guid? TenantId { get; protected set; } + + public virtual DateTimeOffset LastSignInTime { get; protected set; } + + public virtual DateTimeOffset? LastNotificationTime { get; protected set; } + + public virtual InactiveUserStatus Status { get; protected set; } + + public virtual DateTimeOffset? DeactivatedTime { get; protected set; } + + protected IdentityUserInactive() + { + + } + + public IdentityUserInactive( + Guid userId, + DateTimeOffset lastSignInTime, + Guid? tenantId = null) + { + UserId = userId; + TenantId = tenantId; + LastSignInTime = lastSignInTime; + Status = InactiveUserStatus.Notified; + } + + public void MarkNotified(DateTimeOffset now) + { + LastNotificationTime = now; + Status = InactiveUserStatus.Notified; + } + + public void MarkDeactivated(DateTimeOffset now) + { + DeactivatedTime = now; + Status = InactiveUserStatus.Deactivated; + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs new file mode 100644 index 000000000..3f458a83c --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.Identity.Session; + +public class IdentitySessionUserInactiveSynchronizer : + IDistributedEventHandler>, + ITransientDependency +{ + private readonly IIdentityUserInactiveRepository _identityUserInactiveRepository; + + public IdentitySessionUserInactiveSynchronizer(IIdentityUserInactiveRepository identityUserInactiveRepository) + { + _identityUserInactiveRepository = identityUserInactiveRepository; + } + + [UnitOfWork] + public async virtual Task HandleEventAsync(EntityCreatedEto eventData) + { + var userInactive = await _identityUserInactiveRepository.FindByUserIdAsync(eventData.Entity.UserId); + if (userInactive == null) + { + await _identityUserInactiveRepository.DeleteAsync(userInactive); + } + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs index e0c915521..f89c9c1bc 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs @@ -2,6 +2,8 @@ using Volo.Abp.Identity; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.Threading; namespace LINGYUN.Abp.Identity.EntityFrameworkCore; @@ -9,7 +11,7 @@ namespace LINGYUN.Abp.Identity.EntityFrameworkCore; [DependsOn(typeof(Volo.Abp.Identity.EntityFrameworkCore.AbpIdentityEntityFrameworkCoreModule))] public class AbpIdentityEntityFrameworkCoreModule : AbpModule { - // private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); public override void ConfigureServices(ServiceConfigurationContext context) { @@ -19,20 +21,28 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + + options.AddRepository(); }); } - //public override void PostConfigureServices(ServiceConfigurationContext context) - //{ - // OneTimeRunner.Run(() => - // { - // ObjectExtensionManager.Instance - // .MapEfCoreProperty( - // ExtensionIdentityUserConsts.AvatarUrlField, - // (etb, prop) => - // { - // prop.HasMaxLength(ExtensionIdentityUserConsts.MaxAvatarUrlLength); - // }); - // }); - //} + public override void PostConfigureServices(ServiceConfigurationContext context) + { + OneTimeRunner.Run(() => + { + //ObjectExtensionManager.Instance + // .MapEfCoreProperty( + // ExtensionIdentityUserConsts.AvatarUrlField, + // (etb, prop) => + // { + // prop.HasMaxLength(ExtensionIdentityUserConsts.MaxAvatarUrlLength); + // }); + + ObjectExtensionManager.Instance + .MapEfCoreDbContext(builder => + { + builder.ConfigureIdentityUserInactive(); + }); + }); + } } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserInactiveRepository.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserInactiveRepository.cs new file mode 100644 index 000000000..01a2b7460 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserInactiveRepository.cs @@ -0,0 +1,100 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Identity; +using Volo.Abp.Identity.EntityFrameworkCore; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.Identity.EntityFrameworkCore; + +public class EfCoreIdentityUserInactiveRepository : EfCoreRepository, IIdentityUserInactiveRepository +{ + public EfCoreIdentityUserInactiveRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async virtual Task FindByUserIdAsync( + Guid userId, + CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync()) + .Where(x => x.UserId == userId) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task GetInactiveUserCountAsync( + DateTime threshold, + IEnumerable exceptUserIds = null, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var ignoreUserIds = dbContext.Set() + .Select(x => x.UserId); + + return await dbContext.Set() + .WhereIf(exceptUserIds?.Count() > 0, x => !exceptUserIds.Contains(x.Id)) + .Where(x => !ignoreUserIds.Contains(x.Id)) + .Where(x => x.IsActive && + ((x.LastSignInTime.HasValue && x.LastSignInTime < threshold) || + // 更新到abp新版后用户未登陆过使用上次修改时间作为判断依据? + // (x.LastModificationTime.HasValue && x.LastModificationTime < threshold) || + x.CreationTime < threshold)) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetInactiveUserListAsync( + DateTime threshold, + IEnumerable exceptUserIds = null, + string sorting = nameof(IdentityUser.LastSignInTime), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var ignoreUserIds = dbContext.Set() + .Select(x => x.UserId); + + return await dbContext.Set() + .WhereIf(exceptUserIds?.Count() > 0, x => !exceptUserIds.Contains(x.Id)) + .Where(x => !ignoreUserIds.Contains(x.Id)) + .Where(x => x.IsActive && + ((x.LastSignInTime.HasValue && x.LastSignInTime < threshold) || + // 更新到abp新版后用户未登陆过使用上次修改时间作为判断依据? + // (x.LastModificationTime.HasValue && x.LastModificationTime < threshold) || + x.CreationTime < threshold)) + .OrderBy(!sorting.IsNullOrWhiteSpace() ? sorting : nameof(IdentityUser.LastSignInTime)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync()) + .Where(specification.ToExpression()) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListAsync( + ISpecification specification, + string sorting = nameof(IdentityUserInactive.CreationTime), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync()) + .Where(specification.ToExpression()) + .OrderBy(!sorting.IsNullOrWhiteSpace() ? sorting : nameof(IdentityUserInactive.CreationTime)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/IdentityUserInactiveDbContextModelBuilderExtensions.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/IdentityUserInactiveDbContextModelBuilderExtensions.cs new file mode 100644 index 000000000..6ddeda70c --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.EntityFrameworkCore/LINGYUN/Abp/Identity/EntityFrameworkCore/IdentityUserInactiveDbContextModelBuilderExtensions.cs @@ -0,0 +1,23 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Modeling; +using Volo.Abp.Identity; + +namespace LINGYUN.Abp.Identity.EntityFrameworkCore; + +public static class IdentityUserInactiveDbContextModelBuilderExtensions +{ + public static void ConfigureIdentityUserInactive([NotNull] this ModelBuilder builder) + { + builder.Entity(b => + { + b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "UserInactives", AbpIdentityDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.HasIndex(x => new { x.TenantId, x.UserId }); + + b.ApplyObjectExtensionMappings(); + }); + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN.Abp.Identity.Notifications.csproj b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN.Abp.Identity.Notifications.csproj index 46484be63..9295ef1b6 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN.Abp.Identity.Notifications.csproj +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN.Abp.Identity.Notifications.csproj @@ -13,6 +13,13 @@ + + + + + + + diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/AbpIdentityNotificationsModule.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/AbpIdentityNotificationsModule.cs index da3d7c73b..c11ec023f 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/AbpIdentityNotificationsModule.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/AbpIdentityNotificationsModule.cs @@ -1,6 +1,9 @@ using LINGYUN.Abp.Notifications; using Volo.Abp.Domain; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; namespace LINGYUN.Abp.Identity.Notifications; @@ -10,5 +13,18 @@ namespace LINGYUN.Abp.Identity.Notifications; typeof(AbpIdentityDomainSharedModule))] public class AbpIdentityNotificationsModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/LINGYUN/Abp/Identity/Notifications/Localization/Resources"); + }); + } } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationDefinitionProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationDefinitionProvider.cs index 0bcfe88ff..337751200 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationDefinitionProvider.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationDefinitionProvider.cs @@ -24,15 +24,27 @@ public class IdentityNotificationDefinitionProvider : NotificationDefinitionProv NotificationProviderNames.SignalR, // 实时通知处理会话过期事件 NotificationProviderNames.Emailing); // 邮件通知会话过期 + // 账号保持活跃通知 group.AddNotification( - IdentityNotificationNames.IdentityUser.CleaningUpInactiveUsers, - L("Notifications:CleaningUpInactiveUsers"), - L("Notifications:CleaningUpInactiveUsers"), - NotificationType.Application, + IdentityNotificationNames.IdentityUser.InactiveUserReminderNotifier, + L("InactiveUserReminderNotifier"), + L("InactiveUserReminderNotifier"), + NotificationType.User, NotificationLifetime.Persistent, - NotificationContentType.Markdown, + NotificationContentType.Html, allowSubscriptionToClients: false) // 客户端禁用, 所有新用户必须订阅此通知 .WithProviders(NotificationProviderNames.Emailing); + // 账号停用通知 + group.AddNotification( + IdentityNotificationNames.IdentityUser.InactiveUserDeactivationNotifier, + L("InactiveUserDeactivationNotifier"), + L("InactiveUserDeactivationNotifier"), + NotificationType.User, + NotificationLifetime.Persistent, + NotificationContentType.Html, + allowSubscriptionToClients: false) // 客户端禁用, 所有新用户必须订阅此通知 + .WithProviders(NotificationProviderNames.Emailing); + // 账号删除通知不需要添加,直接发送邮件通知即可,因为发布通知时用户已删除 } private static ILocalizableString L(string name) diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationNames.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationNames.cs index 3ee5aed89..b78eaae9b 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationNames.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/IdentityNotificationNames.cs @@ -16,8 +16,16 @@ public static class IdentityNotificationNames { public const string Prefix = GroupName + ".IdentityUser"; /// - /// 不活跃用户清理通知 + /// 账户保持活跃通知 /// - public const string CleaningUpInactiveUsers = Prefix + ".CleaningUpInactiveUsers"; + public const string InactiveUserReminderNotifier = Prefix + ".InactiveUserReminderNotifier"; + /// + /// 账户停用通知 + /// + public const string InactiveUserDeactivationNotifier = Prefix + ".InactiveUserDeactivationNotifier"; + /// + /// 账户删除通知 + /// + public const string InactiveUserDeletionNotifier = Prefix + ".InactiveUserDeletionNotifier"; } } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/en.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/en.json new file mode 100644 index 000000000..24e84a1d6 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/en.json @@ -0,0 +1,29 @@ +{ + "culture": "en", + "texts": { + "InactiveUserReminderNotifier": "Account Activity Reminder", + "InactiveUserDeactivationNotifier": "Account Deactivation Notice", + "InactiveUserDeletionNotifier": "Account Deletion Notice", + "InactiveUserReminderHeader": "Account Activity Reminder", + "InactiveUserReminderWarning": "We have noticed that your account has been inactive for an extended period. To keep your account active and secure, we recommend logging in.", + "InactiveUserReminderAction": "If you wish to keep your account, please log in before", + "InactiveUserReminderReactivate": ".", + "InactiveUserReminderClosure": "If you no longer need this account, no action is required. However, please note that if you do not log in before", + "InactiveUserReminderInactive": ", your account will be deactivated, and you will not be able to log in.", + "InactiveUserDeactivationNotice": "This notice is to inform you that, due to", + "InactiveUserDeactivationWarning": "consecutive days of inactivity, your account has been deactivated. Your data is still stored but inaccessible. If needed, please contact us before", + "InactiveUserDeactivationAction": "to restore your account. If not addressed in time, your account will be permanently deleted.", + "NoReactionClosure": "If you do not wish to reactivate your account, no further action is required. After the reactivation period ends, your account will be automatically queued for deletion.", + "AutomatedNotification": "This is an automated notification. Please do not reply directly to this email.", + "InactiveUserDeactivationHeader": "Account Deactivation Notice", + "InactiveUserDeletionHeader": "Account Deletion Notice", + "InactiveUserDeletionNotice": "Due to prolonged inactivity and failure to respond to previous notices, your account has been permanently deleted. All data associated with you has been removed from the platform.", + "WhatYouCanDo": "What you can do:", + "CreateNewAccountInstructions": "To continue using the service, please", + "CreateNewAccountStep1": "Create a new account", + "CreateNewAccountStep2": "Set up your profile", + "CreateNewAccountStep3": "Resubscribe to services", + "LastSignInTime": "Last sign-in time", + "SignInToAccount": "Sign in to account" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/zh-Hans.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..4c1f2247c --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Localization/Resources/zh-Hans.json @@ -0,0 +1,29 @@ +{ + "culture": "zh-Hans", + "texts": { + "InactiveUserReminderNotifier": "账户保持活跃通知", + "InactiveUserDeactivationNotifier": "账户停用通知", + "InactiveUserDeletionNotifier": "账户删除通知", + "InactiveUserReminderHeader": "账户保持活跃提醒", + "InactiveUserReminderWarning": "我们注意到您的账户已经长时间没有活动,为保持您的账户活跃和安全,建议您登录账户.", + "InactiveUserReminderAction": "如果您想保留您的账号,请在", + "InactiveUserReminderReactivate": "之前登录.", + "InactiveUserReminderClosure": "如果您不再需要此账户,则无需采取任何操作.但请注意,如果截止", + "InactiveUserReminderInactive": "之前您仍未登录账号,系统将禁用您的账号,此时您将无法登录您的账号.", + "InactiveUserDeactivationNotice": "此通知旨在告知您,由于您已连续", + "InactiveUserDeactivationWarning": "天未登录,您的账号已被禁用,您的数据仍被存储但无法访问,如果有需要可在", + "InactiveUserDeactivationAction": "之前联系我们恢复账号,如未及时处理账号将被永久删除.", + "NoReactionClosure": "如果您不希望重新激活账户,则无需采取进一步操作.重新激活期限过后,您的账户将自动进入删除队列.", + "AutomatedNotification": "这是自动发送的通知, 请勿直接回复此邮件.", + "InactiveUserDeactivationHeader": "账户停用通知", + "InactiveUserDeletionHeader": "账户删除通知", + "InactiveUserDeletionNotice": "由于长期不活跃且未响应之前的通知,您的账户已被永久删除,与您相关的数据已从平台中移除.", + "WhatYouCanDo": "您可以:", + "CreateNewAccountInstructions": "如需继续使用服务,请", + "CreateNewAccountStep1": "创建新账户", + "CreateNewAccountStep2": "设置个人资料", + "CreateNewAccountStep3": "重新订阅服务", + "LastSignInTime": "上次登录时间", + "SignInToAccount": "登录账号" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/IdentityNotificationTemplateDefinitionProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/IdentityNotificationTemplateDefinitionProvider.cs new file mode 100644 index 000000000..6111c06b3 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/IdentityNotificationTemplateDefinitionProvider.cs @@ -0,0 +1,34 @@ +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; +using Volo.Abp.TextTemplating; + +namespace LINGYUN.Abp.Identity.Notifications.Templates; + +public class IdentityNotificationTemplateDefinitionProvider : TemplateDefinitionProvider +{ + public override void Define(ITemplateDefinitionContext context) + { + context.Add( + new TemplateDefinition( + IdentityNotificationNames.IdentityUser.InactiveUserReminderNotifier, + displayName: L("InactiveUserReminderNotifier"), + localizationResource: typeof(IdentityResource) + ).WithVirtualFilePath("/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserReminderNotifier.tpl", true), + new TemplateDefinition( + IdentityNotificationNames.IdentityUser.InactiveUserDeactivationNotifier, + displayName: L("InactiveUserDeactivationNotifier"), + localizationResource: typeof(IdentityResource) + ).WithVirtualFilePath("/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeactivationNotifier.tpl", true), + new TemplateDefinition( + IdentityNotificationNames.IdentityUser.InactiveUserDeletionNotifier, + displayName: L("InactiveUserDeletionNotifier"), + localizationResource: typeof(IdentityResource) + ).WithVirtualFilePath("/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeletionNotifier.tpl", true) + ); + } + + private static ILocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeactivationNotifier.tpl b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeactivationNotifier.tpl new file mode 100644 index 000000000..c5e4156e7 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeactivationNotifier.tpl @@ -0,0 +1,33 @@ + + + + + {{L "InactiveUserDeactivationNotifier"}} + + + + + + +
+ + + + + + + +
+

{{L "InactiveUserDeactivationHeader"}}

+
+

{{model.email}}

+

+ {{L "InactiveUserDeactivationNotice"}}{{model.inactivityDays}}{{L "InactiveUserDeactivationWarning"}} + {{model.reactivateDate | date.to_string '%F'}}{{L "InactiveUserDeactivationAction"}} +

+

{{L "NoReactionClosure"}}

+

{{L "AutomatedNotification"}}

+
+
+ + \ No newline at end of file diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeletionNotifier.tpl b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeletionNotifier.tpl new file mode 100644 index 000000000..3388ba945 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserDeletionNotifier.tpl @@ -0,0 +1,30 @@ + + + + + {{L "InactiveUserDeletionNotifier"}} + + + + + + +
+ + + + + + + +
+

{{L "InactiveUserDeletionHeader"}}

+
+

{{model.email}}

+

{{L "InactiveUserDeletionNotice"}}

+

{{L "WhatYouCanDo"}} {{L "CreateNewAccountInstructions"}}{{L "CreateNewAccountStep1"}},{{L "CreateNewAccountStep2"}},{{L "CreateNewAccountStep3"}}.

+

{{L "AutomatedNotification"}}

+
+
+ + \ No newline at end of file diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserReminderNotifier.tpl b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserReminderNotifier.tpl new file mode 100644 index 000000000..b00cc704a --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Notifications/LINGYUN/Abp/Identity/Notifications/Templates/InactiveUserReminderNotifier.tpl @@ -0,0 +1,36 @@ + + + + + {{L "InactiveUserReminderNotifier"}} + + + + + + +
+ + + + + + + +
+

{{L "InactiveUserReminderHeader"}}

+
+

{{model.email}}

+

{{L "InactiveUserReminderWarning"}}

+

{{L "LastSignInTime"}}: {{if model.lastSignInTime}}{{model.lastSignInTime | date.to_string '%F'}}{{else}}{{L "Never"}}{{end}}, + {{L "InactiveUserReminderAction"}}{{model.reactivateDate | date.to_string '%F'}}{{L "InactiveUserReminderReactivate"}} +

+

+ {{L "InactiveUserReminderClosure"}}{{model.reactivateDate | date.to_string '%F'}}{{L "InactiveUserReminderInactive"}} +

+

{{L "SignInToAccount"}}

+

{{L "AutomatedNotification"}}

+
+
+ + \ No newline at end of file diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs index 9ebac6603..0e04081cc 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs @@ -269,15 +269,21 @@ public class SettingAppService : ApplicationService, ISettingAppService, ISettin var signinSetting = identitySetting.AddSetting(L["DisplayName:Identity.SignIn"], L["Description:Identity.SignIn"]); signinSetting.AddDetail( - await SettingDefinitionManager.GetAsync(IdentitySettingNames.SignIn.EnablePhoneNumberConfirmation), + await SettingDefinitionManager.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail), StringLocalizerFactory, - await SettingManager.GetOrNullAsync(IdentitySettingNames.SignIn.EnablePhoneNumberConfirmation, providerName, providerKey), + await SettingManager.GetOrNullAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, providerName, providerKey), ValueType.Boolean, providerName); signinSetting.AddDetail( - await SettingDefinitionManager.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail), + await SettingDefinitionManager.GetAsync(IdentitySettingNames.SignIn.RequireEmailVerificationToRegister), StringLocalizerFactory, - await SettingManager.GetOrNullAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, providerName, providerKey), + await SettingManager.GetOrNullAsync(IdentitySettingNames.SignIn.RequireEmailVerificationToRegister, providerName, providerKey), + ValueType.Boolean, + providerName); + signinSetting.AddDetail( + await SettingDefinitionManager.GetAsync(IdentitySettingNames.SignIn.EnablePhoneNumberConfirmation), + StringLocalizerFactory, + await SettingManager.GetOrNullAsync(IdentitySettingNames.SignIn.EnablePhoneNumberConfirmation, providerName, providerKey), ValueType.Boolean, providerName); signinSetting.AddDetail( @@ -362,6 +368,18 @@ public class SettingAppService : ApplicationService, ISettingAppService, ISettin await SettingManager.GetOrNullAsync(IdentitySettingNames.Password.PasswordChangePeriodDays, providerName, providerKey), ValueType.Number, providerName); + passwordSetting.AddDetail( + await SettingDefinitionManager.GetAsync(IdentitySettingNames.Password.EnablePreventPasswordReuse), + StringLocalizerFactory, + await SettingManager.GetOrNullAsync(IdentitySettingNames.Password.EnablePreventPasswordReuse, providerName, providerKey), + ValueType.Boolean, + providerName); + passwordSetting.AddDetail( + await SettingDefinitionManager.GetAsync(IdentitySettingNames.Password.PreventPasswordReuseCount), + StringLocalizerFactory, + await SettingManager.GetOrNullAsync(IdentitySettingNames.Password.PreventPasswordReuseCount, providerName, providerKey), + ValueType.Number, + providerName); #endregion @@ -395,10 +413,22 @@ public class SettingAppService : ApplicationService, ISettingAppService, ISettin ValueType.Number, providerName); - settingGroups.AddGroup(identitySetting); + #endregion + + #region 链接 + + var linkSetting = identitySetting.AddSetting(L["DisplayName:Identity.Link"], L["Description:Identity.Link"]); + linkSetting.AddDetail( + await SettingDefinitionManager.GetAsync(LINGYUN.Abp.Identity.Settings.IdentitySettingNames.Link.UserLoginUri), + StringLocalizerFactory, + await SettingManager.GetOrNullAsync(LINGYUN.Abp.Identity.Settings.IdentitySettingNames.Link.UserLoginUri, providerName, providerKey), + ValueType.String, + providerName); #endregion + settingGroups.AddGroup(identitySetting); + #endregion #region 邮件设置 diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj index e397f5ea8..0b74e457f 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj @@ -18,6 +18,10 @@
+ + + + diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/AbpIdentityJobsModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/AbpIdentityJobsModule.cs index 518b0f3df..92aae6ba2 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/AbpIdentityJobsModule.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/AbpIdentityJobsModule.cs @@ -1,5 +1,6 @@ using LINGYUN.Abp.BackgroundTasks; using LINGYUN.Abp.Identity.Notifications; +using Volo.Abp.Emailing; using Volo.Abp.Identity.Localization; using Volo.Abp.Localization; using Volo.Abp.Modularity; @@ -7,6 +8,7 @@ using Volo.Abp.VirtualFileSystem; namespace LINGYUN.Abp.Identity.Jobs; +[DependsOn(typeof(AbpEmailingModule))] [DependsOn(typeof(AbpIdentityDomainModule))] [DependsOn(typeof(AbpIdentityNotificationsModule))] [DependsOn(typeof(AbpBackgroundTasksAbstractionsModule))] @@ -22,7 +24,7 @@ public class AbpIdentityJobsModule : AbpModule Configure(options => { options.Resources - .Add() + .Get() .AddVirtualJson("/LINGYUN/Abp/Identity/Jobs/Localization/Resources"); }); } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/IdentityJobDefinitionProvider.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/IdentityJobDefinitionProvider.cs index 8b65287e8..4cdb4a532 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/IdentityJobDefinitionProvider.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/IdentityJobDefinitionProvider.cs @@ -10,12 +10,17 @@ public class IdentityJobDefinitionProvider : JobDefinitionProvider InactiveIdentitySessionCleanupJob.Name, typeof(InactiveIdentitySessionCleanupJob), LocalizableStatic.Create("InactiveIdentitySessionCleanupJob"), - InactiveIdentitySessionCleanupJob.Paramters) - // TODO: 实现用户过期清理作业需要增加用户会话实体 - //new JobDefinition( - // InactiveIdentityUserCleanupJob.Name, - // typeof(InactiveIdentityUserCleanupJob), - // LocalizableStatic.Create("InactiveIdentityUserCleanupJob")) + InactiveIdentitySessionCleanupJob.Paramters), + new JobDefinition( + InactiveIdentityUserNotifierJob.Name, + typeof(InactiveIdentityUserNotifierJob), + LocalizableStatic.Create("InactiveIdentityUserNotifierJob"), + InactiveIdentityUserNotifierJob.Paramters), + new JobDefinition( + InactiveIdentityUserCleanupJob.Name, + typeof(InactiveIdentityUserCleanupJob), + LocalizableStatic.Create("InactiveIdentityUserCleanupJob"), + InactiveIdentityUserCleanupJob.Paramters) ); } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserCleanupJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserCleanupJob.cs index c577f18d0..69055d319 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserCleanupJob.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserCleanupJob.cs @@ -1,125 +1,293 @@ -//using LINGYUN.Abp.BackgroundTasks; -//using LINGYUN.Abp.Identity.Notifications; -//using LINGYUN.Abp.Notifications; -//using Microsoft.Extensions.Logging; -//using System.Collections.Generic; -//using System.Linq; -//using System.Threading.Tasks; -//using Volo.Abp.Domain.Repositories; -//using Volo.Abp.Identity; -//using Volo.Abp.Specifications; -//using Volo.Abp.Timing; - -//namespace LINGYUN.Abp.Identity.Jobs; - -///// -///// 用户清理作业 -///// -///// -///// 清理长期未登录用户 -///// -//public class InactiveIdentityUserCleanupJob : IJobRunnable -//{ -// public const string Name = "InactiveIdentityUserCleanupJob"; - -// #region Definition Paramters - -// public readonly static IReadOnlyList Paramters = -// new List -// { -// new JobDefinitionParamter( -// PropertyUserInactiveCleanupDays, -// LocalizableStatic.Create("DisplayName:UserInactiveCleanupDays"), -// LocalizableStatic.Create("Description:UserInactiveCleanupDays")), -// new JobDefinitionParamter( -// PropertyUserInactiveNotifierDays, -// LocalizableStatic.Create("DisplayName:UserInactiveNotifierDays"), -// LocalizableStatic.Create("Description:UserInactiveNotifierDays")), -// }; - -// #endregion -// /// -// /// 不活跃用户清理时间, 单位: 天 -// /// -// public const string PropertyUserInactiveCleanupDays = "UserInactiveCleanupDays"; -// /// -// /// 不活跃用户通知时间, 单位: 天 -// /// -// public const string PropertyUserInactiveNotifierDays = "UserInactiveNotifierDays"; - -// public async virtual Task ExecuteAsync(JobRunnableContext context) -// { -// var logger = context.GetRequiredService>(); - -// // 不活跃用户清理时间 -// var inactiveCleanupDays = context.GetOrDefaultJobData(PropertyUserInactiveCleanupDays, 30); -// // 不活跃用户通知时间 -// var inactiveNotifierDays = context.GetOrDefaultJobData(PropertyUserInactiveNotifierDays, 180); - -// var clock = context.GetRequiredService(); -// var identityUserRepo = context.GetRequiredService(); -// var identityUserSessionRepo = context.GetRequiredService(); - -// // 获取需要清理的用户集合 -// var specification = new ExpressionSpecification( -// x => x.LastAccessed <= clock.Now.AddDays(-inactiveNotifierDays)); - -// using (identityUserSessionRepo.DisableTracking()) -// { -// var inactiveUserCount = await identityUserSessionRepo.GetCountAsync(specification); -// if (inactiveUserCount == 0) -// { -// logger.LogInformation("There are no inactive users to be notified."); -// return; -// } -// // 不活跃用户会话集合 -// var inactiveUsers = await identityUserSessionRepo.GetListAsync(specification, maxResultCount: inactiveUserCount); - -// // 直接清理的不活跃用户集合 -// var inactiveCleanupUsers = inactiveUsers.Where(x => x.LastAccessed <= clock.Now.AddDays(-inactiveCleanupDays)); - -// // 需要通知的不活跃用户 -// var inactiveNotifierUsers = inactiveUsers.ExceptBy(inactiveCleanupUsers.Select(x => x.Id), x => x.Id); -// if (inactiveNotifierUsers.Count() != 0) -// { -// await SendInactiveUserNotifier(context, inactiveNotifierUsers); -// } - -// if (inactiveCleanupUsers.Count() != 0) -// { -// logger.LogInformation( -// "Prepare to clean up {count} users who have been inactive for more than {inactiveCleanupDays} days.", -// inactiveCleanupUsers.Count(), -// inactiveCleanupDays); - -// // 清理不活跃用户 -// await identityUserRepo.DeleteManyAsync(inactiveCleanupUsers.Select(x => x.UserId)); -// } -// } -// logger.LogInformation($"Cleaned inactive users."); -// } - -// /// -// /// 发送不活跃用户清理通知 -// /// -// /// -// /// -// /// -// private async Task SendInactiveUserNotifier(JobRunnableContext context, IEnumerable userSessions) -// { -// // TODO: 完成不活跃用户清理通知 -// var notificationSender = context.GetRequiredService(); - -// var notificationTemplate = new NotificationTemplate( -// IdentityNotificationNames.IdentityUser.CleaningUpInactiveUsers, -// data: new Dictionary -// { - -// }); - -// await notificationSender.SendNofiterAsync( -// IdentityNotificationNames.IdentityUser.CleaningUpInactiveUsers, -// notificationTemplate -// ); -// } -//} +using LINGYUN.Abp.BackgroundTasks; +using LINGYUN.Abp.Identity.Notifications; +using LINGYUN.Abp.Notifications; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Emailing; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Specifications; +using Volo.Abp.TextTemplating; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.Identity.Jobs; + +/// +/// 不活跃用户清理作业 +/// +/// +/// 清理长期不活跃用户 +/// +public class InactiveIdentityUserCleanupJob : IJobRunnable +{ + public const string Name = "InactiveIdentityUserCleanupJob"; + + #region Definition Paramters + + public readonly static IReadOnlyList Paramters = + new List + { + new JobDefinitionParamter( + PropertyInactivityPeriodDays, + LocalizableStatic.Create("DisplayName:InactivityPeriodDays"), + LocalizableStatic.Create("Description:InactivityPeriodDays")), + new JobDefinitionParamter( + PropertyGracePeriodDays, + LocalizableStatic.Create("DisplayName:GracePeriodDays"), + LocalizableStatic.Create("Description:GracePeriodDays")), + }; + + #endregion + /// + /// 停用不活跃用户天数 + /// + public const string PropertyInactivityPeriodDays = "InactivityPeriodDays"; + /// + /// 已停用用户宽限天数 + /// + public const string PropertyGracePeriodDays = "GracePeriodDays"; + + public async virtual Task ExecuteAsync(JobRunnableContext context) + { + await Task.WhenAll([ + SetInactiveIdentityUsers(context), + DeleteInactiveIdentityUsers(context) + ]); + } + + protected async virtual Task SetInactiveIdentityUsers(JobRunnableContext context) + { + // 不活跃用户停用时间: 用户距离上次登录天数 + 宽限天数 + var inactivityPeriodDays = context.GetOrDefaultJobData(PropertyInactivityPeriodDays, 180); + var gracePeriodDays = context.GetOrDefaultJobData(PropertyGracePeriodDays, 60); + + var clock = context.GetRequiredService(); + var logger = context.GetRequiredService>(); + + var identityUserRepo = context.GetRequiredService(); + var identityUserInactiveRepo = context.GetRequiredService(); + + var specification = new ExpressionSpecification( + x => x.Status == InactiveUserStatus.Notified && x.LastSignInTime < clock.Now.AddDays(-(inactivityPeriodDays + gracePeriodDays))); + + var inactiveUserCount = await identityUserInactiveRepo.GetCountAsync(specification); + if (inactiveUserCount == 0) + { + logger.LogInformation("There are no inactive users that can be deactivated."); + return; + } + + var inactiveUserBatch = 1000; + + while (true) + { + var identityUserInactives = await identityUserInactiveRepo.GetListAsync( + specification, + maxResultCount: inactiveUserBatch); + if (identityUserInactives.Count == 0) + { + logger.LogInformation("There are no inactive users that can be deactivated."); + break; + } + + var inactiveUsers = await identityUserRepo.GetListByIdsAsync( + identityUserInactives.Select(x => x.UserId)); + if (inactiveUsers.Count > 0) + { + inactiveUsers.ForEach((inactiveUser) => + { + inactiveUser.SetIsActive(false); + }); + + await identityUserRepo.UpdateManyAsync(inactiveUsers); + + await SendInactiveUserDeactivationNotifier(context, inactiveUsers); + } + + identityUserInactives.ForEach((identityUserInactive) => + { + identityUserInactive.MarkDeactivated(clock.Now); + }); + + await identityUserInactiveRepo.UpdateManyAsync(identityUserInactives); + + if (identityUserInactives.Count < inactiveUserBatch) + { + break; + } + } + + logger.LogInformation("The operation to deactivate inactive users has been successfully completed."); + } + + /// + /// 发送不活跃用户停用通知 + /// + /// + /// + /// + protected async virtual Task SendInactiveUserDeactivationNotifier(JobRunnableContext context, IEnumerable inactiveUsers) + { + var clock = context.GetRequiredService(); + var notificationSender = context.GetRequiredService(); + + var inactivityPeriodDays = context.GetOrDefaultJobData(PropertyInactivityPeriodDays, 180); + var gracePeriodDays = context.GetOrDefaultJobData(PropertyGracePeriodDays, 60); + + var reactivateDate = clock.Now.AddDays(gracePeriodDays); + await Parallel.ForEachAsync( + inactiveUsers, + context.CancellationToken, + async (inactiveUser, ctx) => + { + var inactivityDays = (int)(clock.Now - (inactiveUser.LastSignInTime ?? inactiveUser.CreationTime)).TotalDays; + var notificationTemplateData = new Dictionary + { + { "now", clock.Now }, + { "name", inactiveUser.Name }, + { "userName", inactiveUser.UserName }, + { "surname", inactiveUser.Surname }, + { "email", inactiveUser.Email }, + { "isActive", inactiveUser.IsActive }, + { "inactivityDays", inactivityDays }, + { "reactivateDate", reactivateDate }, + { "creationTime", clock.Normalize(inactiveUser.CreationTime) }, + }; + if (inactiveUser.LastSignInTime.HasValue) + { + notificationTemplateData["lastSignInTime"] = clock.Normalize(inactiveUser.LastSignInTime.Value.DateTime); + } + var notificationTemplate = new NotificationTemplate( + IdentityNotificationNames.IdentityUser.InactiveUserDeactivationNotifier, + data: notificationTemplateData); + + await notificationSender.SendNofiterAsync( + IdentityNotificationNames.IdentityUser.InactiveUserDeactivationNotifier, + template: notificationTemplate, + user: new UserIdentifier(inactiveUser.Id, inactiveUser.UserName), + tenantId: inactiveUser.TenantId, + severity: NotificationSeverity.Warn); + }); + } + + protected async virtual Task DeleteInactiveIdentityUsers(JobRunnableContext context) + { + // 不活跃用户删除时间: 距离上次发送不活跃通知天数 + 宽限天数 + var gracePeriodDays = context.GetOrDefaultJobData(PropertyGracePeriodDays, 60); + + var clock = context.GetRequiredService(); + var logger = context.GetRequiredService>(); + + var identityUserRepo = context.GetRequiredService(); + var identityUserInactiveRepo = context.GetRequiredService(); + + var specification = new ExpressionSpecification( + x => x.Status == InactiveUserStatus.Deactivated && x.DeactivatedTime < clock.Now.AddDays(-gracePeriodDays)); + + var inactiveUserCount = await identityUserInactiveRepo.GetCountAsync(specification); if (inactiveUserCount == 0) + { + logger.LogInformation("There are no inactive users to delete."); + return; + } + + var inactiveUserBatch = 1000; + + while (true) + { + var identityUserInactives = await identityUserInactiveRepo.GetListAsync( + specification, + maxResultCount: inactiveUserBatch); + if (identityUserInactives.Count == 0) + { + logger.LogInformation("There are no inactive users to delete."); + break; + } + + await identityUserInactiveRepo.DeleteManyAsync(identityUserInactives); + + var inactiveUsers = await identityUserRepo.GetListByIdsAsync( + identityUserInactives.Select(x => x.UserId)); + if (inactiveUsers.Count > 0) + { + await identityUserRepo.DeleteManyAsync(inactiveUsers); + + await SendInactiveUserDeletionNotifier(context, inactiveUsers); + } + + if (identityUserInactives.Count < inactiveUserBatch) + { + break; + } + } + + logger.LogInformation("The operation to deactivate inactive users has been successfully completed."); + } + + /// + /// 发送不活跃用户删除通知 + /// + /// + /// + /// + protected async virtual Task SendInactiveUserDeletionNotifier(JobRunnableContext context, IEnumerable inactiveUsers) + { + var clock = context.GetRequiredService(); + var emailSender = context.GetRequiredService(); + var templateRenderer = context.GetRequiredService(); + var logger = context.GetRequiredService>(); + var stringLocalizer = context.GetRequiredService>(); + + var emailTitle = stringLocalizer["InactiveUserDeletionNotifier"]; + var gracePeriodDays = context.GetOrDefaultJobData(PropertyGracePeriodDays, 60); + var inactivityPeriodDays = context.GetOrDefaultJobData(PropertyInactivityPeriodDays, 180); + + await Parallel.ForEachAsync( + inactiveUsers, + context.CancellationToken, + async (inactiveUser, ctx) => + { + if (!inactiveUser.EmailConfirmed) + { + logger.LogWarning("{userName} email has not been confirmed, skipping the account deletion notification sending.", inactiveUser.UserName); + return; + } + try + { + var notificationTemplateData = new Dictionary + { + { "now", clock.Now }, + { "name", inactiveUser.Name }, + { "userName", inactiveUser.UserName }, + { "surname", inactiveUser.Surname }, + { "email", inactiveUser.Email }, + { "isActive", inactiveUser.IsActive }, + { "inactivityPeriodDays", inactivityPeriodDays }, + { "gracePeriodDays", gracePeriodDays }, + { "creationTime", clock.Normalize(inactiveUser.CreationTime) }, + }; + if (inactiveUser.LastSignInTime.HasValue) + { + notificationTemplateData["lastSignInTime"] = clock.Normalize(inactiveUser.LastSignInTime.Value.DateTime); + } + + var emailBody = await templateRenderer.RenderAsync( + IdentityNotificationNames.IdentityUser.InactiveUserDeletionNotifier, + notificationTemplateData); + + await emailSender.SendAsync( + inactiveUser.Email, + emailTitle, + emailBody, + isBodyHtml: true); + } + catch (Exception ex) + { + logger.LogWarning("Failure in sending the email for notifying the deletion of the user {userName}, error: {message}", inactiveUser.UserName, ex.Message); + } + }); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserNotifierJob.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserNotifierJob.cs new file mode 100644 index 000000000..1998ef196 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/InactiveIdentityUserNotifierJob.cs @@ -0,0 +1,179 @@ +using LINGYUN.Abp.BackgroundTasks; +using LINGYUN.Abp.Identity.Notifications; +using LINGYUN.Abp.Identity.Settings; +using LINGYUN.Abp.Notifications; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DistributedLocking; +using Volo.Abp.Identity; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Roles; +using Volo.Abp.Settings; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.Identity.Jobs; + +/// +/// 不活跃用户通知作业 +/// +/// +/// 通知长期未登录用户保持账号活跃 +/// +public class InactiveIdentityUserNotifierJob : IJobRunnable +{ + public const string Name = "InactiveIdentityUserNotifierJob"; + + #region Definition Paramters + + public readonly static IReadOnlyList Paramters = + new List + { + new JobDefinitionParamter( + PropertyInactivityPeriodDays, + LocalizableStatic.Create("DisplayName:InactivityPeriodDays"), + LocalizableStatic.Create("Description:InactivityPeriodDays")), + }; + + #endregion + /// + /// 不活跃用户通知时间, 单位: 天 + /// + public const string PropertyInactivityPeriodDays = "InactivityPeriodDays"; + + public async virtual Task ExecuteAsync(JobRunnableContext context) + { + var logger = context.GetRequiredService>(); + + var currentTenant = context.GetRequiredService(); + var distributedLock = context.GetRequiredService(); + var distributedLockKey = $"{nameof(InactiveIdentityUserNotifierJob)}_{currentTenant.Id}"; + await using var jobLockHandle = await distributedLock.TryAcquireAsync(distributedLockKey); + if (jobLockHandle == null) + { + logger.LogInformation("Handle is null because of the locking for : {distributedLockKey}", distributedLockKey); + return; + } + + logger.LogInformation("Lock is acquired for {distributedLockKey}.", distributedLockKey); + + // 不活跃用户通知时间 + var inactiveNotifierDays = context.GetOrDefaultJobData(PropertyInactivityPeriodDays, 180); + // 排除系统管理员用户 + var exceptUserIds = new List(); + + var clock = context.GetRequiredService(); + + var identityRoleManager = context.GetRequiredService(); + var identityUserManager = context.GetRequiredService(); + var identityUserRepo = context.GetRequiredService(); + var identityUserInactiveRepo = context.GetRequiredService(); + + // 管理员角色用户不清理 + var adminRoleUsers = await identityUserRepo.GetListByNormalizedRoleNameAsync( + identityRoleManager.NormalizeKey(AbpRoleConsts.AdminRoleName)); + if (adminRoleUsers.Count > 0) + { + exceptUserIds.AddIfNotContains(adminRoleUsers.Select(x => x.Id)); + } + // 管理员用户不清理 + var adminUsers = await identityUserRepo.GetUsersByNormalizedUserNameAsync( + identityUserManager.NormalizeName("admin")); + if (adminUsers.Count > 0) + { + exceptUserIds.AddIfNotContains(adminUsers.Select(x => x.Id)); + } + + var inactiveUserNotifierTime = clock.Now.AddDays(-inactiveNotifierDays); + + var inactiveUserCount = await identityUserInactiveRepo.GetInactiveUserCountAsync( + inactiveUserNotifierTime, + exceptUserIds); + if (inactiveUserCount == 0) + { + logger.LogInformation("There are no inactive users to be notified."); + return; + } + var inactiveUserBatch = 1000; + + while (true) + { + var inactiveUsers = await identityUserInactiveRepo.GetInactiveUserListAsync( + inactiveUserNotifierTime, + exceptUserIds, + maxResultCount: inactiveUserBatch); + if (inactiveUsers.Count == 0) + { + logger.LogInformation("There are no inactive users to be notified."); + break; + } + + var identityUserInactives = inactiveUsers.Select(user => + new IdentityUserInactive( + user.Id, + user.LastSignInTime ?? user.LastModificationTime ?? user.CreationTime, + user.TenantId)); + + await identityUserInactiveRepo.InsertManyAsync(identityUserInactives); + + await SendInactiveUserReminderNotifier(context, inactiveUsers); + + if (inactiveUsers.Count < inactiveUserBatch) + { + break; + } + } + + logger.LogInformation($"The job of sending notifications to inactive users has been successfully completed.."); + } + + /// + /// 发送不活跃用户提醒通知 + /// + /// + /// + /// + private async Task SendInactiveUserReminderNotifier(JobRunnableContext context, IEnumerable inactiveUsers) + { + var clock = context.GetRequiredService(); + var settingProvider = context.GetRequiredService(); + var notificationSender = context.GetRequiredService(); + + var userLoginUri = await settingProvider.GetOrNullAsync(IdentitySettingNames.Link.UserLoginUri); + var inactiveNotifierDays = context.GetOrDefaultJobData(PropertyInactivityPeriodDays, 180); + var reactivateDate = clock.Now.AddDays(inactiveNotifierDays); + await Parallel.ForEachAsync( + inactiveUsers, + context.CancellationToken, + async (inactiveUser, ctx) => + { + var notificationTemplateData = new Dictionary + { + { "now", clock.Now }, + { "loginUrl", userLoginUri }, + { "name", inactiveUser.Name }, + { "userName", inactiveUser.UserName }, + { "surname", inactiveUser.Surname }, + { "email", inactiveUser.Email }, + { "isActive", inactiveUser.IsActive }, + { "reactivateDate", reactivateDate }, + { "creationTime", clock.Normalize(inactiveUser.CreationTime) }, + }; + if (inactiveUser.LastSignInTime.HasValue) + { + notificationTemplateData["lastSignInTime"] = clock.Normalize(inactiveUser.LastSignInTime.Value.DateTime); + } + var notificationTemplate = new NotificationTemplate( + IdentityNotificationNames.IdentityUser.InactiveUserReminderNotifier, + data: notificationTemplateData); + + await notificationSender.SendNofiterAsync( + IdentityNotificationNames.IdentityUser.InactiveUserReminderNotifier, + template: notificationTemplate, + user: new UserIdentifier(inactiveUser.Id, inactiveUser.UserName), + tenantId: inactiveUser.TenantId); + }); + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/en.json b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/en.json index 97e971ee2..c6ccf70b1 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/en.json +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/en.json @@ -2,8 +2,13 @@ "culture": "en", "texts": { "InactiveIdentitySessionCleanupJob": "Inactive Session Cleanup Job", + "InactiveIdentityUserNotifierJob": "Inactive User Notifier Job", "InactiveIdentityUserCleanupJob": "Inactive User Cleanup Job", "DisplayName:SessionInactiveDays": "Duration of inactive conversation", - "Description:SessionInactiveDays": "Duration of inactive conversation, unit: days." + "Description:SessionInactiveDays": "Duration of inactive conversation, unit: days.", + "DisplayName:InactivityPeriodDays": "Inactivity Period Days", + "Description:InactivityPeriodDays": "The duration since the last login, in units of days, defaults to 180 days if it is empty.", + "DisplayName:GracePeriodDays": "Grace Period Days", + "Description:GracePeriodDays": "The duration since the account was deactivated, in units of days. If the value is empty, it defaults to 60 days." } } \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/zh-Hans.json b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/zh-Hans.json index 3fd0242bd..f007e1ebf 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN/Abp/Identity/Jobs/Localization/Resources/zh-Hans.json @@ -2,8 +2,13 @@ "culture": "zh-Hans", "texts": { "InactiveIdentitySessionCleanupJob": "不活跃会话清理作业", + "InactiveIdentityUserNotifierJob": "不活跃用户通知作业", "InactiveIdentityUserCleanupJob": "不活跃用户清理作业", "DisplayName:SessionInactiveDays": "不活跃会话保持时长", - "Description:SessionInactiveDays": "不活跃会话保持时长,单位: 天." + "Description:SessionInactiveDays": "不活跃会话保持时长,单位: 天.", + "DisplayName:InactivityPeriodDays": "不活跃账号期限", + "Description:InactivityPeriodDays": "距离上次登录以来的时长,单位:天,为空时默认180天.", + "DisplayName:GracePeriodDays": "停用账号宽限期限", + "Description:GracePeriodDays": "距离账号停用以来的时长,单位:天,为空时默认60天." } } \ No newline at end of file diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Local/UserCreateSubscribeIdentityNotificationsEventHandler.cs b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Local/UserCreateSubscribeIdentityNotificationsEventHandler.cs new file mode 100644 index 000000000..2e4be61bf --- /dev/null +++ b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Local/UserCreateSubscribeIdentityNotificationsEventHandler.cs @@ -0,0 +1,39 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.Users; + +namespace LY.MicroService.Applications.Single.EventBus.Local; + +public class UserCreateSubscribeIdentityNotificationsEventHandler : ILocalEventHandler>, ITransientDependency +{ + private readonly INotificationSubscriptionManager _notificationSubscriptionManager; + public UserCreateSubscribeIdentityNotificationsEventHandler( + INotificationSubscriptionManager notificationSubscriptionManager + ) + { + _notificationSubscriptionManager = notificationSubscriptionManager; + } + + public async virtual Task HandleEventAsync(EntityCreatedEventData eventData) + { + var userIdentifer = new UserIdentifier(eventData.Entity.Id, eventData.Entity.UserName); + // 订阅用户会话过期通知 + await _notificationSubscriptionManager + .SubscribeAsync( + eventData.Entity.TenantId, + userIdentifer, + IdentityNotificationNames.Session.ExpirationSession); + // 订阅用户账号不活跃通知 + await _notificationSubscriptionManager + .SubscribeAsync( + eventData.Entity.TenantId, + userIdentifer, + IdentityNotificationNames.IdentityUser.InactiveUserReminderNotifier); + // 订阅用户账号停用通知 + await _notificationSubscriptionManager + .SubscribeAsync( + eventData.Entity.TenantId, + userIdentifer, + IdentityNotificationNames.IdentityUser.InactiveUserDeactivationNotifier); + } +} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index e238f4cc1..d2265159c 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -265,6 +265,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index fdd8aee01..fc1ef5c75 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -1,5 +1,6 @@ using LINGYUN.Abp.BlobManagement.MimeCheck; using LINGYUN.Abp.Exporter.MiniSoftware; +using LINGYUN.Abp.Identity.Jobs; using LINGYUN.Abp.Notifications.Calendar; namespace LY.MicroService.Applications.Single; @@ -267,6 +268,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpBackgroundTasksNotificationsModule), // 后台任务模块 Quartz集成 typeof(AbpBackgroundTasksQuartzModule), + // 后台任务模块 身份认证模块作业 + typeof(AbpIdentityJobsModule), // 数据审计模块 应用服务 typeof(AbpDataProtectionManagementApplicationModule), diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Local/UserSubscribeSessionExpirationEventHandler.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Local/UserSubscribeSessionExpirationEventHandler.cs index cc2deae80..71dc66ef7 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Local/UserSubscribeSessionExpirationEventHandler.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Local/UserSubscribeSessionExpirationEventHandler.cs @@ -25,11 +25,16 @@ public class UserSubscribeSessionExpirationEventHandler : ILocalEventHandler + @@ -66,6 +67,8 @@ + + diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs index 1344f0cf4..2d859354a 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs @@ -8,14 +8,17 @@ using LINGYUN.Abp.BackgroundTasks.ExceptionHandling; using LINGYUN.Abp.BackgroundTasks.Jobs; using LINGYUN.Abp.BackgroundTasks.Notifications; using LINGYUN.Abp.BackgroundTasks.Quartz; +using LINGYUN.Abp.BlobManagement; using LINGYUN.Abp.Claims.Mapping; using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.Elasticsearch.Jobs; using LINGYUN.Abp.Emailing.Platform; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.Identity.EntityFrameworkCore; +using LINGYUN.Abp.Identity.Jobs; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; -using LINGYUN.Abp.BlobManagement; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; @@ -64,9 +67,12 @@ namespace LY.MicroService.TaskManagement; typeof(AbpBackgroundTasksDistributedLockingModule), typeof(AbpBackgroundTasksExceptionHandlingModule), typeof(AbpBackgroundTasksNotificationsModule), + typeof(AbpElasticsearchJobsModule), + typeof(AbpIdentityJobsModule), typeof(TaskManagementApplicationModule), typeof(TaskManagementHttpApiModule), typeof(TaskManagementEntityFrameworkCoreModule), + typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpFeatureManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), From 5d748d189fe65b1e98b8a9f83d6884d32413ab0c Mon Sep 17 00:00:00 2001 From: ruanbl Date: Thu, 4 Jun 2026 10:53:50 +0800 Subject: [PATCH 22/40] fix userInactiveDeleteNull --- .../Session/IdentitySessionUserInactiveSynchronizer.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs index 3f458a83c..8c26cdfb6 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs @@ -1,10 +1,4 @@ -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events.Distributed; -using Volo.Abp.EventBus.Distributed; -using Volo.Abp.Uow; - -namespace LINGYUN.Abp.Identity.Session; +namespace LINGYUN.Abp.Identity.Session; public class IdentitySessionUserInactiveSynchronizer : IDistributedEventHandler>, @@ -21,7 +15,7 @@ public class IdentitySessionUserInactiveSynchronizer : public async virtual Task HandleEventAsync(EntityCreatedEto eventData) { var userInactive = await _identityUserInactiveRepository.FindByUserIdAsync(eventData.Entity.UserId); - if (userInactive == null) + if (userInactive != null) { await _identityUserInactiveRepository.DeleteAsync(userInactive); } From 041d113d8ff71a2d360242b02ae0aa2870d7af37 Mon Sep 17 00:00:00 2001 From: zhang Date: Mon, 8 Jun 2026 21:58:54 +0200 Subject: [PATCH 23/40] fix(vben5): update vxe toolbar refresh config --- .../src/components/tools/AIToolDefinitionTable.vue | 3 ++- .../src/components/workspaces/WorkspaceDefinitionTable.vue | 3 ++- .../@abp/auditing/src/components/audit-logs/AuditLogTable.vue | 3 ++- .../@abp/auditing/src/components/loggings/LoggingTable.vue | 3 ++- .../src/components/containers/BlobContainerTable.vue | 3 ++- .../src/components/entity-type-infos/EntityTypeInfoTable.vue | 3 ++- .../packages/@abp/demo/src/components/books/BookTable.vue | 3 ++- apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue | 3 ++- .../identity/src/components/claim-types/ClaimTypeTable.vue | 3 ++- .../organization-units/OrganizationUnitRoleTable.vue | 3 ++- .../organization-units/OrganizationUnitUserTable.vue | 3 ++- .../src/components/organization-units/SelectMemberModal.vue | 3 ++- .../src/components/organization-units/SelectRoleModal.vue | 3 ++- .../packages/@abp/identity/src/components/roles/RoleTable.vue | 3 ++- .../identity/src/components/security-logs/SecurityLogTable.vue | 3 ++- .../@abp/identity/src/components/sessions/SessionTable.vue | 3 ++- .../packages/@abp/identity/src/components/users/UserTable.vue | 3 ++- .../src/components/my-notifilers/MyNotificationTable.vue | 3 ++- .../components/send-records/NotificationSendRecordTable.vue | 3 ++- .../src/components/applications/ApplicationTable.vue | 3 ++- .../src/components/authorizations/AuthorizationTable.vue | 3 ++- .../@abp/openiddict/src/components/scopes/ScopeTable.vue | 3 ++- .../@abp/openiddict/src/components/tokens/TokenTable.vue | 3 ++- .../@abp/oss/src/components/containers/ContainerTable.vue | 3 ++- .../packages/@abp/oss/src/components/objects/FileList.vue | 3 ++- .../@abp/platform/src/components/layouts/LayoutTable.vue | 3 ++- .../src/components/messages/email/EmailMessageTable.vue | 3 ++- .../platform/src/components/messages/sms/SmsMessageTable.vue | 3 ++- .../@abp/saas/src/components/editions/EditionTable.vue | 3 ++- .../packages/@abp/saas/src/components/tenants/TenantTable.vue | 3 ++- .../@abp/tasks/src/components/job-infos/JobInfoTable.vue | 3 ++- .../src/components/send-attempts/WebhookSendAttemptTable.vue | 3 ++- .../src/components/subscriptions/WebhookSubscriptionTable.vue | 3 ++- 33 files changed, 66 insertions(+), 33 deletions(-) diff --git a/apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue b/apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue index fe687793c..72ebd68af 100644 --- a/apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue +++ b/apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue @@ -140,7 +140,8 @@ const gridOptions: VxeGridProps = { custom: true, export: true, // import: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionTable.vue b/apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionTable.vue index d59fb691e..dc35d5766 100644 --- a/apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionTable.vue +++ b/apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionTable.vue @@ -130,7 +130,8 @@ const gridOptions: VxeGridProps = { custom: true, export: true, // import: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue b/apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue index d841a8a50..7aa2848b8 100644 --- a/apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue +++ b/apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue @@ -241,7 +241,8 @@ const gridOptions: VxeGridProps = { custom: true, export: true, // import: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue b/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue index edb0db0a0..d4bd06923 100644 --- a/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue +++ b/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue @@ -278,7 +278,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/blob-management/src/components/containers/BlobContainerTable.vue b/apps/vben5/packages/@abp/blob-management/src/components/containers/BlobContainerTable.vue index 2f544fe6f..832fa8162 100644 --- a/apps/vben5/packages/@abp/blob-management/src/components/containers/BlobContainerTable.vue +++ b/apps/vben5/packages/@abp/blob-management/src/components/containers/BlobContainerTable.vue @@ -109,7 +109,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/data-protection/src/components/entity-type-infos/EntityTypeInfoTable.vue b/apps/vben5/packages/@abp/data-protection/src/components/entity-type-infos/EntityTypeInfoTable.vue index 37b37e797..574e3f8ee 100644 --- a/apps/vben5/packages/@abp/data-protection/src/components/entity-type-infos/EntityTypeInfoTable.vue +++ b/apps/vben5/packages/@abp/data-protection/src/components/entity-type-infos/EntityTypeInfoTable.vue @@ -91,7 +91,8 @@ const gridOptions: VxeGridProps = { }, }, toolbarConfig: { - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, }, diff --git a/apps/vben5/packages/@abp/demo/src/components/books/BookTable.vue b/apps/vben5/packages/@abp/demo/src/components/books/BookTable.vue index c524544e0..858f22175 100644 --- a/apps/vben5/packages/@abp/demo/src/components/books/BookTable.vue +++ b/apps/vben5/packages/@abp/demo/src/components/books/BookTable.vue @@ -108,7 +108,8 @@ const gridOptions: VxeGridProps = { }, }, toolbarConfig: { - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, }, diff --git a/apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue b/apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue index 1f9ae1025..5b178c969 100644 --- a/apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue +++ b/apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue @@ -84,7 +84,8 @@ const gridOptions: VxeGridProps = { }, }, toolbarConfig: { - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, }, diff --git a/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue b/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue index 7b37c661b..8c734494f 100644 --- a/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue @@ -154,7 +154,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitRoleTable.vue b/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitRoleTable.vue index 1475e6845..65ba22b48 100644 --- a/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitRoleTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitRoleTable.vue @@ -84,7 +84,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue b/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue index 70a828d36..c05f4f373 100644 --- a/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue @@ -90,7 +90,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectMemberModal.vue b/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectMemberModal.vue index e3d584027..75b9cad29 100644 --- a/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectMemberModal.vue +++ b/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectMemberModal.vue @@ -112,7 +112,8 @@ const gridOptions: VxeGridProps = { }, }, toolbarConfig: { - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, }, diff --git a/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectRoleModal.vue b/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectRoleModal.vue index 9f34ab20f..119b91936 100644 --- a/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectRoleModal.vue +++ b/apps/vben5/packages/@abp/identity/src/components/organization-units/SelectRoleModal.vue @@ -104,7 +104,8 @@ const gridOptions: VxeGridProps = { }, }, toolbarConfig: { - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, }, diff --git a/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue b/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue index 85aad1ba7..d27a64700 100644 --- a/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue @@ -120,7 +120,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue b/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue index ef0910f31..3bb2160ca 100644 --- a/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue @@ -185,7 +185,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue b/apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue index 54811c8d7..ec20c6987 100644 --- a/apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue @@ -168,7 +168,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue b/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue index 520e3d659..91db5a725 100644 --- a/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue @@ -168,7 +168,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/notifications/src/components/my-notifilers/MyNotificationTable.vue b/apps/vben5/packages/@abp/notifications/src/components/my-notifilers/MyNotificationTable.vue index 7d824f144..4a35f4522 100644 --- a/apps/vben5/packages/@abp/notifications/src/components/my-notifilers/MyNotificationTable.vue +++ b/apps/vben5/packages/@abp/notifications/src/components/my-notifilers/MyNotificationTable.vue @@ -175,7 +175,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/notifications/src/components/send-records/NotificationSendRecordTable.vue b/apps/vben5/packages/@abp/notifications/src/components/send-records/NotificationSendRecordTable.vue index 6ac0201c5..275f0b0fe 100644 --- a/apps/vben5/packages/@abp/notifications/src/components/send-records/NotificationSendRecordTable.vue +++ b/apps/vben5/packages/@abp/notifications/src/components/send-records/NotificationSendRecordTable.vue @@ -234,7 +234,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationTable.vue b/apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationTable.vue index 76d5f5bec..8860b6d61 100644 --- a/apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationTable.vue +++ b/apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationTable.vue @@ -146,7 +146,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/openiddict/src/components/authorizations/AuthorizationTable.vue b/apps/vben5/packages/@abp/openiddict/src/components/authorizations/AuthorizationTable.vue index b80a267ca..fb2364db5 100644 --- a/apps/vben5/packages/@abp/openiddict/src/components/authorizations/AuthorizationTable.vue +++ b/apps/vben5/packages/@abp/openiddict/src/components/authorizations/AuthorizationTable.vue @@ -168,7 +168,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/openiddict/src/components/scopes/ScopeTable.vue b/apps/vben5/packages/@abp/openiddict/src/components/scopes/ScopeTable.vue index fca6fab93..1cdc7da32 100644 --- a/apps/vben5/packages/@abp/openiddict/src/components/scopes/ScopeTable.vue +++ b/apps/vben5/packages/@abp/openiddict/src/components/scopes/ScopeTable.vue @@ -121,7 +121,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/openiddict/src/components/tokens/TokenTable.vue b/apps/vben5/packages/@abp/openiddict/src/components/tokens/TokenTable.vue index 42f254e0d..11aafb492 100644 --- a/apps/vben5/packages/@abp/openiddict/src/components/tokens/TokenTable.vue +++ b/apps/vben5/packages/@abp/openiddict/src/components/tokens/TokenTable.vue @@ -195,7 +195,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue b/apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue index c1e54e87a..ca6db4fcf 100644 --- a/apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue +++ b/apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue @@ -120,7 +120,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue b/apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue index ed831162b..34af7586c 100644 --- a/apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue +++ b/apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue @@ -150,7 +150,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: false, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue b/apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue index ab95a2651..7d3301f6c 100644 --- a/apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue +++ b/apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue @@ -144,7 +144,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/platform/src/components/messages/email/EmailMessageTable.vue b/apps/vben5/packages/@abp/platform/src/components/messages/email/EmailMessageTable.vue index ff8a59da4..ca9b8f00d 100644 --- a/apps/vben5/packages/@abp/platform/src/components/messages/email/EmailMessageTable.vue +++ b/apps/vben5/packages/@abp/platform/src/components/messages/email/EmailMessageTable.vue @@ -207,7 +207,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/platform/src/components/messages/sms/SmsMessageTable.vue b/apps/vben5/packages/@abp/platform/src/components/messages/sms/SmsMessageTable.vue index de596fc83..a967b4200 100644 --- a/apps/vben5/packages/@abp/platform/src/components/messages/sms/SmsMessageTable.vue +++ b/apps/vben5/packages/@abp/platform/src/components/messages/sms/SmsMessageTable.vue @@ -188,7 +188,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/saas/src/components/editions/EditionTable.vue b/apps/vben5/packages/@abp/saas/src/components/editions/EditionTable.vue index e8ed79ccd..b23665a05 100644 --- a/apps/vben5/packages/@abp/saas/src/components/editions/EditionTable.vue +++ b/apps/vben5/packages/@abp/saas/src/components/editions/EditionTable.vue @@ -103,7 +103,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/saas/src/components/tenants/TenantTable.vue b/apps/vben5/packages/@abp/saas/src/components/tenants/TenantTable.vue index e7973cee5..db6724f09 100644 --- a/apps/vben5/packages/@abp/saas/src/components/tenants/TenantTable.vue +++ b/apps/vben5/packages/@abp/saas/src/components/tenants/TenantTable.vue @@ -128,7 +128,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoTable.vue b/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoTable.vue index f656debe9..a2976b94b 100644 --- a/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoTable.vue +++ b/apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoTable.vue @@ -387,7 +387,8 @@ const gridOptions: VxeGridProps = { }, }, toolbarConfig: { - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, }, diff --git a/apps/vben5/packages/@abp/webhooks/src/components/send-attempts/WebhookSendAttemptTable.vue b/apps/vben5/packages/@abp/webhooks/src/components/send-attempts/WebhookSendAttemptTable.vue index ac89bb49d..dbe1913f2 100644 --- a/apps/vben5/packages/@abp/webhooks/src/components/send-attempts/WebhookSendAttemptTable.vue +++ b/apps/vben5/packages/@abp/webhooks/src/components/send-attempts/WebhookSendAttemptTable.vue @@ -211,7 +211,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, diff --git a/apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue b/apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue index 0634ecaff..7f5952a9c 100644 --- a/apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue +++ b/apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue @@ -210,7 +210,8 @@ const gridOptions: VxeGridProps = { toolbarConfig: { custom: true, export: true, - refresh: { + refresh: true, + refreshOptions: { code: 'query', }, zoom: true, From 24828043ef08c6e344c0fa1e99ada34a18041c5a Mon Sep 17 00:00:00 2001 From: zhang Date: Tue, 9 Jun 2026 23:44:34 +0200 Subject: [PATCH 24/40] fix(vben5): display audit log help url --- .../@abp/auditing/src/components/loggings/LoggingDrawer.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue b/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue index 2db94f182..ede5a944e 100644 --- a/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue +++ b/apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue @@ -219,7 +219,7 @@ async function onGet(id: string) { {{ row.hResult }} - {{ row.helpURL }} + {{ row.helpUrl }} From 2cbfc05810a3781dbe52d33180b3eaffe1f3a7b3 Mon Sep 17 00:00:00 2001 From: zhang Date: Tue, 9 Jun 2026 23:59:04 +0200 Subject: [PATCH 25/40] fix(identity): add missing session synchronizer usings --- .../Session/IdentitySessionUserInactiveSynchronizer.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs index 8c26cdfb6..022bb26d6 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/Session/IdentitySessionUserInactiveSynchronizer.cs @@ -1,4 +1,10 @@ -namespace LINGYUN.Abp.Identity.Session; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.Identity.Session; public class IdentitySessionUserInactiveSynchronizer : IDistributedEventHandler>, From 5e1bff6b842391946a13c42c619f0a5abdb7a3e8 Mon Sep 17 00:00:00 2001 From: colin Date: Tue, 16 Jun 2026 08:25:29 +0800 Subject: [PATCH 26/40] feat(wechat): Add unit tests for the WeChat encryption library --- .../LINGYUN.Abp.WeChat.Common.Tests.csproj | 25 +++++++ .../WeChat/Common/AbpWeChatCommonTestBase.cs | 7 ++ .../Common/AbpWeChatCommonTestModule.cs | 11 +++ .../Abp/WeChat/Common/Crypto/Crypto_Tests.cs | 69 +++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN.Abp.WeChat.Common.Tests.csproj create mode 100644 aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestBase.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestModule.cs create mode 100644 aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/Crypto/Crypto_Tests.cs diff --git a/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN.Abp.WeChat.Common.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN.Abp.WeChat.Common.Tests.csproj new file mode 100644 index 000000000..2d94c78c7 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN.Abp.WeChat.Common.Tests.csproj @@ -0,0 +1,25 @@ + + + + net10.0 + + false + Debug;Release + AnyCPU + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestBase.cs new file mode 100644 index 000000000..b4eebc5cc --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestBase.cs @@ -0,0 +1,7 @@ +using LINGYUN.Abp.Tests; + +namespace LINGYUN.Abp.WeChat.Common; + +public abstract class AbpWeChatCommonTestBase : AbpTestsBase +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestModule.cs new file mode 100644 index 000000000..26086eab2 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonTestModule.cs @@ -0,0 +1,11 @@ +using LINGYUN.Abp.Tests; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.WeChat.Common; + +[DependsOn( + typeof(AbpWeChatCommonModule), + typeof(AbpTestsBaseModule))] +public class AbpWeChatCommonTestModule : AbpModule +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/Crypto/Crypto_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/Crypto/Crypto_Tests.cs new file mode 100644 index 000000000..01e28a7c7 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN/Abp/WeChat/Common/Crypto/Crypto_Tests.cs @@ -0,0 +1,69 @@ +using LINGYUN.Abp.WeChat.Common.Utils; +using Shouldly; +using System.Xml; +using Xunit; + +namespace LINGYUN.Abp.WeChat.Common.Crypto; + +public class Crypto_Tests : AbpWeChatCommonTestBase +{ + private const string sToken = "QDG6eK"; + private const string sCorpID = "wx5823bf96d3bd56c7"; + private const string sEncodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"; + + [Fact] + public void CryptTest() + { + var wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID); + // string sVerifyMsgSig = HttpUtils.ParseUrl("msg_signature"); + string sVerifyMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"; + // string sVerifyTimeStamp = HttpUtils.ParseUrl("timestamp"); + string sVerifyTimeStamp = "1409659589"; + // string sVerifyNonce = HttpUtils.ParseUrl("nonce"); + string sVerifyNonce = "263014780"; + // string sVerifyEchoStr = HttpUtils.ParseUrl("echostr"); + string sVerifyEchoStr = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="; + int ret = 0; + string sEchoStr = ""; + ret = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr, ref sEchoStr); + + ret.ShouldBe(0); + + // string sReqTimeStamp = HttpUtils.ParseUrl("timestamp"); + string sReqTimeStamp = "1409659813"; + // string sReqNonce = HttpUtils.ParseUrl("nonce"); + string sReqNonce = "1372623149"; + + string sRespData = "13488318601234567890123456128"; + string sEncryptMsg = ""; //xml格式的密文 + ret = wxcpt.EncryptMsg(sRespData, sReqTimeStamp, sReqNonce, ref sEncryptMsg); + + ret.ShouldBe(0); + } + + [Fact] + public void DecryptTest() + { + var wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID); + + string sReqMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6"; + // string sReqTimeStamp = HttpUtils.ParseUrl("timestamp"); + string sReqTimeStamp = "1409659813"; + // string sReqNonce = HttpUtils.ParseUrl("nonce"); + string sReqNonce = "1372623149"; + // Post请求的密文数据 + // string sReqData = HttpUtils.PostData(); + string sReqData = ""; + string sMsg = ""; // 解析之后的明文 + var ret = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData, ref sMsg); + + ret.ShouldBe(0); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(sMsg); + XmlNode root = doc.FirstChild; + string content = root["Content"].InnerText; + + content.ShouldNotBeNullOrWhiteSpace(); + } +} From 4579fc3a6ddbf5598b81eff92947e73b706da0e9 Mon Sep 17 00:00:00 2001 From: colin Date: Tue, 16 Jun 2026 11:11:13 +0800 Subject: [PATCH 27/40] feat: Implement password reuse check --- .../LINGYUN/Abp/Account/ProfileAppService.cs | 65 +++++++++++++++++++ .../Abp/Identity/IdentityErrorCodes.cs | 4 ++ .../LINGYUN/Abp/Identity/Localization/en.json | 1 + .../Abp/Identity/Localization/zh-Hans.json | 1 + .../Abp/Identity/AbpIdentityDomainModule.cs | 3 +- .../PasswordHistoryPasswordValidator.cs | 33 ++++++++++ 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/ProfileAppService.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PasswordHistoryPasswordValidator.cs diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/ProfileAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/ProfileAppService.cs new file mode 100644 index 000000000..e78e0013a --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/ProfileAppService.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Account; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Settings; +using Volo.Abp.Settings; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.Account; + +[Dependency(ReplaceServices = true)] +public class ProfileAppService : Volo.Abp.Account.ProfileAppService +{ + public ProfileAppService( + IdentityUserManager userManager, + IOptions identityOptions) + : base(userManager, identityOptions) + { + } + + public async override Task ChangePasswordAsync(ChangePasswordInput input) + { + await IdentityOptions.SetAsync(); + + var currentUser = await UserManager.GetByIdAsync(CurrentUser.GetId()); + + if (currentUser.IsExternal) + { + throw new BusinessException(code: IdentityErrorCodes.ExternalUserPasswordChange); + } + + if (currentUser.PasswordHash.IsNullOrWhiteSpace()) + { + (await UserManager.AddPasswordAsync(currentUser, input.NewPassword)).CheckErrors(); + } + else + { + (await UserManager.ChangePasswordAsync(currentUser, input.CurrentPassword, input.NewPassword)).CheckErrors(); + } + + if (await SettingProvider.IsTrueAsync(IdentitySettingNames.Password.EnablePreventPasswordReuse)) + { + var preventPasswordReuseCount = await SettingProvider.GetAsync(IdentitySettingNames.Password.PreventPasswordReuseCount, 6); + currentUser.AddPasswordHistory(input.NewPassword); + if (currentUser.PasswordHistories.Count > preventPasswordReuseCount) + { + var excessCount = currentUser.PasswordHistories.Count - preventPasswordReuseCount; + var oldestHistories = currentUser.PasswordHistories + .OrderBy(x => x.CreatedAt) + .Take(excessCount) + .ToList(); + + foreach (var history in oldestHistories) + { + currentUser.PasswordHistories.Remove(history); + } + } + } + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityErrorCodes.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityErrorCodes.cs index ab60c20ba..3b1f90c3b 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityErrorCodes.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityErrorCodes.cs @@ -34,4 +34,8 @@ public class IdentityErrorCodes /// 验证器验证无效 ///
public const string AuthenticatorTokenInValid = "Volo.Abp.Identity:020012"; + /// + /// 密码不能与最近{0}次使用的密码相同 + /// + public const string PasswordInHistoryInValid = "Volo.Abp.Identity:020013"; } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json index 5ed0b7b6c..82450d78d 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json @@ -53,6 +53,7 @@ "Volo.Abp.Identity:020010": "The email address is bound!", "Volo.Abp.Identity:020011": "Secondary authentication cannot be enabled when an MFA device is not attached!", "Volo.Abp.Identity:020012": "Invalid authenticator code!", + "Volo.Abp.Identity:020013": "The password cannot be the same as the previous one.!", "Volo.Abp.Identity:DuplicatePhoneNumber": "Phone number '{0}' is already taken.", "DisplayName:Abp.Identity.User.SmsNewUserRegister": "Register sms template", "Description:Abp.Identity.User.SmsNewUserRegister": "When the user registers, he/she should send the template number of the SMS verification code and fill in the template number of the corresponding cloud platform registration", diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json index f2b073d39..4187cf83c 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json @@ -53,6 +53,7 @@ "Volo.Abp.Identity:020010": "邮件地址已绑定!", "Volo.Abp.Identity:020011": "未绑定MFA设备时无法启用二次认证!", "Volo.Abp.Identity:020012": "无效的验证器代码!", + "Volo.Abp.Identity:020013": "密码不能与之前的密码相同!", "Volo.Abp.Identity:DuplicatePhoneNumber": "手机号 '{0}' 已存在.", "DisplayName:Abp.Identity.User.SmsNewUserRegister": "新用户注册模板", "Description:Abp.Identity.User.SmsNewUserRegister": "新用户通过手机注册账号验证码模板", diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs index 7ed5c893e..9ff9e40e7 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/AbpIdentityDomainModule.cs @@ -24,7 +24,8 @@ public class AbpIdentityDomainModule : AbpModule { PreConfigure(builder => { - builder.AddUserValidator(); + builder.AddUserValidator() + .AddPasswordValidator(); }); } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PasswordHistoryPasswordValidator.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PasswordHistoryPasswordValidator.cs new file mode 100644 index 000000000..99986fb29 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/PasswordHistoryPasswordValidator.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Identity.Settings; +using Volo.Abp.Settings; +using IdentityUser = Volo.Abp.Identity.IdentityUser; + +namespace Microsoft.AspNetCore.Identity; + +public class PasswordHistoryPasswordValidator : IPasswordValidator +{ + public async virtual Task ValidateAsync(UserManager manager, IdentityUser user, string password) + { + var settingProvider = manager.ServiceProvider.GetRequiredService(); + if (await settingProvider.IsTrueAsync(IdentitySettingNames.Password.EnablePreventPasswordReuse)) + { + var preventPasswordReuseCount = await settingProvider.GetAsync(IdentitySettingNames.Password.PreventPasswordReuseCount, 6); + if (preventPasswordReuseCount > 0 && user.PasswordHistories.Any(x => x.Password == password)) + { + var localizer = manager.ServiceProvider.GetRequiredService>(); + + return IdentityResult.Failed(new IdentityError + { + Code = LINGYUN.Abp.Identity.IdentityErrorCodes.PasswordInHistoryInValid, + Description = localizer["Volo.Abp.Identity:PasswordInHistory", preventPasswordReuseCount] + }); + } + } + return IdentityResult.Success; + } +} From a5fad6155827a1b23f3fbaeeee6370ceac10197f Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 13:14:31 +0800 Subject: [PATCH 28/40] feat(account): Add support for logging in with link accounts --- .../vben5/apps/app-antd/src/layouts/basic.vue | 42 +++- .../app-antd/src/locales/langs/en-US/abp.json | 1 + .../app-antd/src/locales/langs/zh-CN/abp.json | 1 + apps/vben5/apps/app-antd/src/store/auth.ts | 39 +++- .../src/views/_core/authentication/login.vue | 14 +- .../packages/@abp/account/src/api/index.ts | 1 + .../@abp/account/src/api/useLinkUsersApi.ts | 54 +++++ .../account/src/components/UserLinkModal.vue | 192 ++++++++++++++++ .../@abp/account/src/components/index.ts | 1 + .../@abp/account/src/hooks/useOAuthService.ts | 16 +- .../packages/@abp/account/src/types/index.ts | 2 + .../@abp/account/src/types/link-user.ts | 14 ++ .../packages/@abp/account/src/types/token.ts | 10 + .../packages/@abp/account/src/utils/auth.ts | 25 ++- .../AbpAccountApplicationContractsModule.cs | 18 +- .../Abp/Account/Dto/LinkUserBaseDto.cs | 15 ++ .../LINGYUN/Abp/Account/Dto/LinkUserDto.cs | 29 +++ .../LINGYUN/Abp/Account/Dto/LinkUserInput.cs | 15 ++ .../Abp/Account/Dto/UnLinkUserInput.cs | 7 + .../Abp/Account/Dto/VerifyLinkTokenInput.cs | 14 ++ .../Abp/Account/Dto/VerifyLinkUserDto.cs | 27 +++ .../Abp/Account/Dto/VerifyLinkUserInput.cs | 5 + .../Account/IIdentityLinkUserAppService.cs | 57 +++++ .../Abp/Account/IMyProfileAppService.cs | 1 - .../Account/Localization/Resources/en.json | 13 +- .../Localization/Resources/zh-Hans.json | 13 +- .../Abp/Account/IdentityLinkUserAppService.cs | 170 ++++++++++++++ .../LINGYUN/Abp/Account/AccountController.cs | 140 ++++++------ .../Abp/Account/IdentityLinkUserController.cs | 70 ++++++ .../Controllers/AuthorizeController.cs | 20 +- .../Pages/Account/SelectAccount.cshtml.cs | 2 +- .../Pages/Account/LinkLogged.cshtml | 26 +++ .../Pages/Account/LinkLogged.cshtml.cs | 106 +++++++++ .../Pages/Account/Login.cshtml | 28 ++- .../Pages/Account/Login.cshtml.cs | 208 +++++++++++++++--- .../Pages/Account/Register.cshtml.cs | 97 +++++++- .../Pages/Account/SendCode.cshtml.cs | 20 +- .../Pages/Account/VerifyCode.cshtml.cs | 83 +++++++ .../Abp/Identity/IdentityErrorCodes.cs | 4 + .../LINGYUN/Abp/Identity/Localization/en.json | 1 + .../Abp/Identity/Localization/zh-Hans.json | 1 + .../LinkUser/AbpOpenIddictLinkUserModule.cs | 1 + .../LinkUser/LinkUserAuthorizationHandler.cs | 37 ++++ 43 files changed, 1492 insertions(+), 148 deletions(-) create mode 100644 apps/vben5/packages/@abp/account/src/api/useLinkUsersApi.ts create mode 100644 apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue create mode 100644 apps/vben5/packages/@abp/account/src/types/link-user.ts create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserBaseDto.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserDto.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserInput.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/UnLinkUserInput.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkTokenInput.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserDto.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserInput.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IIdentityLinkUserAppService.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/IdentityLinkUserAppService.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/IdentityLinkUserController.cs create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml.cs create mode 100644 aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/LinkUserAuthorizationHandler.cs diff --git a/apps/vben5/apps/app-antd/src/layouts/basic.vue b/apps/vben5/apps/app-antd/src/layouts/basic.vue index c2682b198..755598abb 100644 --- a/apps/vben5/apps/app-antd/src/layouts/basic.vue +++ b/apps/vben5/apps/app-antd/src/layouts/basic.vue @@ -1,10 +1,10 @@ + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/index.ts b/apps/vben5/packages/@abp/account/src/components/index.ts index 807e2f91a..3bbd032e1 100644 --- a/apps/vben5/packages/@abp/account/src/components/index.ts +++ b/apps/vben5/packages/@abp/account/src/components/index.ts @@ -1,3 +1,4 @@ export { default as MyProfile } from './MyProfile.vue'; export { default as MySetting } from './MySetting.vue'; export { default as QrCodeLogin } from './QrCodeLogin.vue'; +export { default as UserLinkModal } from './UserLinkModal.vue'; diff --git a/apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts b/apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts index 92e064aeb..d5e87dd90 100644 --- a/apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts +++ b/apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts @@ -1,4 +1,7 @@ +import type { SigninRedirectArgs, SignoutRedirectArgs } from 'oidc-client-ts'; + import type { + LinkUserTokenRequest, PasswordTokenRequestModel, PhoneNumberTokenRequest, QrCodeTokenRequest, @@ -7,8 +10,12 @@ import type { import { userManager } from '../utils/auth'; export function useOAuthService() { - async function login() { - return userManager.signinRedirect(); + async function login(args?: SigninRedirectArgs) { + return userManager.signinRedirect(args); + } + + async function loginByLinkUser(input: LinkUserTokenRequest) { + return userManager.signinLinkUser(input); } async function loginByPassword(input: PasswordTokenRequestModel) { @@ -23,8 +30,8 @@ export function useOAuthService() { return userManager.signinQrCode(input); } - async function logout() { - return userManager.signoutRedirect(); + async function logout(args?: SignoutRedirectArgs) { + return userManager.signoutRedirect(args); } async function revokeTokens() { @@ -55,6 +62,7 @@ export function useOAuthService() { return { login, + loginByLinkUser, loginByPassword, loginBySmsCode, loginByQrCode, diff --git a/apps/vben5/packages/@abp/account/src/types/index.ts b/apps/vben5/packages/@abp/account/src/types/index.ts index 0f182a66b..dae3e2f1b 100644 --- a/apps/vben5/packages/@abp/account/src/types/index.ts +++ b/apps/vben5/packages/@abp/account/src/types/index.ts @@ -1,6 +1,8 @@ export * from './account'; export * from './bind'; export * from './external-logins'; +export * from './link-user'; export * from './profile'; export * from './token'; export * from './user'; +export type { SigninRedirectArgs } from 'oidc-client-ts'; diff --git a/apps/vben5/packages/@abp/account/src/types/link-user.ts b/apps/vben5/packages/@abp/account/src/types/link-user.ts new file mode 100644 index 000000000..c80c605f4 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/types/link-user.ts @@ -0,0 +1,14 @@ +interface LinkUserDto { + directlyLinked: boolean; + linkTenantId?: string; + linkTenantName?: string; + linkUserId: string; + linkUserName: string; +} + +interface UnLinkUserInput { + tenantId?: string; + userId: string; +} + +export type { LinkUserDto, UnLinkUserInput }; diff --git a/apps/vben5/packages/@abp/account/src/types/token.ts b/apps/vben5/packages/@abp/account/src/types/token.ts index 653b5cde8..cf06a2e11 100644 --- a/apps/vben5/packages/@abp/account/src/types/token.ts +++ b/apps/vben5/packages/@abp/account/src/types/token.ts @@ -38,6 +38,15 @@ interface PasswordTokenRequestModel { /** 用户名 */ username: string; } +/** 关联用户授权请求数据模型 */ +interface LinkUserTokenRequest { + /** 当前用户访问令牌 */ + accessToken?: string; + /** 关联用户租户Id */ + linkTenantId?: string; + /** 关联用户Id */ + linkUserId: string; +} /** 令牌撤销请求数据类型 */ interface RevokeTokenRequest { /** 令牌 */ @@ -92,6 +101,7 @@ interface ShouldChangePasswordError extends OAuthError { } export type { + LinkUserTokenRequest, OAuthError, OAuthTokenRefreshModel, OAuthTokenResult, diff --git a/apps/vben5/packages/@abp/account/src/utils/auth.ts b/apps/vben5/packages/@abp/account/src/utils/auth.ts index bc15f2775..b32ca9ae9 100644 --- a/apps/vben5/packages/@abp/account/src/utils/auth.ts +++ b/apps/vben5/packages/@abp/account/src/utils/auth.ts @@ -1,6 +1,7 @@ import type { Logger, UserManagerSettings } from 'oidc-client-ts'; import type { + LinkUserTokenRequest, PasswordTokenRequestModel, PhoneNumberTokenRequest, QrCodeTokenRequest, @@ -71,6 +72,28 @@ class AbpUserManager extends UserManager { params.set('userId', model.userId); } } + async signinLinkUser(params: LinkUserTokenRequest) { + const logger = this._logger.create('signinLinkUser'); + const body = new URLSearchParams({ + LinkUserId: params.linkUserId, + grant_type: 'link_user', + client_id: this.settings.client_id, + }); + if (params.accessToken) { + body.set('access_token', params.accessToken); + } + if (params.linkTenantId) { + body.set('LinkTenantId', params.linkTenantId); + } + const client_secret = this.settings.client_secret; + if (client_secret) { + body.set('client_secret', client_secret); + } + this._writeUserId(body, params); + this._writeTenantId(body, params); + this._writeTwoFactorToken(body, params); + return await this._fetchUser(logger, body); + } async signinQrCode(params: QrCodeTokenRequest) { const logger = this._logger.create('signinQrCode'); const client_secret = this.settings.client_secret; @@ -89,7 +112,6 @@ class AbpUserManager extends UserManager { this._writeTwoFactorToken(body, params); return await this._fetchUser(logger, body); } - override async signinResourceOwnerCredentials( params: PasswordTokenRequestModel, ) { @@ -111,7 +133,6 @@ class AbpUserManager extends UserManager { this._writeChangePasswordToken(body, params); return await this._fetchUser(logger, body); } - async signinSmsCode(params: PhoneNumberTokenRequest) { const logger = this._logger.create('signinSmsCode'); const client_secret = this.settings.client_secret; diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/AbpAccountApplicationContractsModule.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/AbpAccountApplicationContractsModule.cs index d78983c51..0302277b5 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/AbpAccountApplicationContractsModule.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/AbpAccountApplicationContractsModule.cs @@ -1,14 +1,14 @@ using Volo.Abp.Account.Localization; using Volo.Abp.Localization; -using Volo.Abp.Modularity; +using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; -namespace LINGYUN.Abp.Account; - -[DependsOn( - typeof(Volo.Abp.Account.AbpAccountApplicationContractsModule))] -public class AbpAccountApplicationContractsModule : AbpModule -{ +namespace LINGYUN.Abp.Account; + +[DependsOn( + typeof(Volo.Abp.Account.AbpAccountApplicationContractsModule))] +public class AbpAccountApplicationContractsModule : AbpModule +{ public override void ConfigureServices(ServiceConfigurationContext context) { Configure(options => @@ -22,5 +22,5 @@ public class AbpAccountApplicationContractsModule : AbpModule .Get() .AddVirtualJson("/LINGYUN/Abp/Account/Localization/Resources"); }); - } -} + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserBaseDto.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserBaseDto.cs new file mode 100644 index 000000000..5038aefb3 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserBaseDto.cs @@ -0,0 +1,15 @@ +using System; + +namespace LINGYUN.Abp.Account.Dto; + +public abstract class LinkUserBaseDto +{ + /// + /// 关联用户Id + /// + public Guid UserId { get; set; } + /// + /// 关联租户Id + /// + public Guid? TenantId { get; set; } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserDto.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserDto.cs new file mode 100644 index 000000000..32707b87b --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserDto.cs @@ -0,0 +1,29 @@ +using System; + +namespace LINGYUN.Abp.Account.Dto; +/// +/// 关联用户Dto +/// +public class LinkUserDto +{ + /// + /// 关联用户Id + /// + public Guid LinkUserId { get; set; } + /// + /// 关联用户名 + /// + public string LinkUserName { get; set; } + /// + /// 关联租户Id + /// + public Guid? LinkTenantId { get; set; } + /// + /// 关联租户名 + /// + public string LinkTenantName { get; set; } + /// + /// 直接关联 + /// + public bool DirectlyLinked { get; set; } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserInput.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserInput.cs new file mode 100644 index 000000000..37c75dfb2 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/LinkUserInput.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.Account.Dto; +/// +/// 关联用户Dto +/// +public class LinkUserInput : LinkUserBaseDto +{ + /// + /// 关联用户Token + /// + [Required] + public string Token { get; set; } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/UnLinkUserInput.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/UnLinkUserInput.cs new file mode 100644 index 000000000..8423f4aac --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/UnLinkUserInput.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.Account.Dto; +/// +/// 取消关联用户Dto +/// +public class UnLinkUserInput : LinkUserBaseDto +{ +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkTokenInput.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkTokenInput.cs new file mode 100644 index 000000000..512c16f03 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkTokenInput.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.Account.Dto; +/// +/// 验证关联用户TokenDto +/// +public class VerifyLinkTokenInput : LinkUserBaseDto +{ + /// + /// 关联用户Token + /// + [Required] + public string Token { get; set; } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserDto.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserDto.cs new file mode 100644 index 000000000..23642f5c9 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserDto.cs @@ -0,0 +1,27 @@ +using System; + +namespace LINGYUN.Abp.Account.Dto; + +public class VerifyLinkUserDto +{ + /// + /// 关联用户Id + /// + public Guid? LinkUserId { get; set; } + /// + /// 关联用户名 + /// + public string LinkUserName { get; set; } + /// + /// 关联租户Id + /// + public Guid? LinkTenantId { get; set; } + /// + /// 关联租户名 + /// + public string LinkTenantName { get; set; } + /// + /// 是否已关联 + /// + public bool IsLinked { get; set; } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserInput.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserInput.cs new file mode 100644 index 000000000..d406c8734 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/VerifyLinkUserInput.cs @@ -0,0 +1,5 @@ +namespace LINGYUN.Abp.Account.Dto; + +public class VerifyLinkUserInput : LinkUserBaseDto +{ +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IIdentityLinkUserAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IIdentityLinkUserAppService.cs new file mode 100644 index 000000000..ed1dfbbd6 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IIdentityLinkUserAppService.cs @@ -0,0 +1,57 @@ +using LINGYUN.Abp.Account.Dto; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.Account; +/// +/// 关联用户应用服务接口 +/// +public interface IIdentityLinkUserAppService : IApplicationService +{ + /// + /// 关联用户 + /// + /// + /// + Task LinkAsync(LinkUserInput input); + /// + /// 取消关联用户 + /// + /// + /// + Task UnlinkAsync(UnLinkUserInput input); + /// + /// 生成关联用户Token + /// + /// + Task GenerateLinkTokenAsync(); + /// + /// 生成关联用户登录Token + /// + /// + Task GenerateLinkLoginTokenAsync(); + /// + /// 获取已关联用户列表 + /// + /// + Task> GetListAsync(); + /// + /// 验证关联用户 + /// + /// + /// + Task VerifyLinkUserAsync(VerifyLinkUserInput input); + /// + /// 验证关联用户Token + /// + /// + /// + Task VerifyLinkTokenAsync(VerifyLinkTokenInput input); + /// + /// 验证关联用户登录Token + /// + /// + /// + Task VerifyLinkLoginTokenAsync(VerifyLinkTokenInput input); +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs index 05f39b352..9a9ec4c1f 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs @@ -1,5 +1,4 @@ using LINGYUN.Abp.Identity; -using System; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/en.json b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/en.json index daf6584b7..c9d9c61fc 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/en.json +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/en.json @@ -17,6 +17,8 @@ "DisplayName:AuthenticatorCode": "Authenticator Code", "DisplayName:PhoneNumber": "Phone Number", "DisplayName:Code": "Code", + "DisplayName:LinkUserName": "User Name", + "DisplayName:DirectlyLinked": "Directly Linked", "TwoFactor": "Two factor authentication", "TwoFactor:Enabled": "TwoFactor Enabled", "TwoFactor:Email": "Email", @@ -67,6 +69,15 @@ "CancelBindWarningMessage": "After unbinding, you will not be able to use an external identity. If you log in through this method, your session will be logged out!", "EmailConfirm": "Email Confirm", "AvatarChanged": "Avatar Changed", - "ClickToValidation": "Click To Validation" + "ClickToValidation": "Click To Validation", + "LinkUser": "Link User", + "LinkUser:New": "New Link User", + "LinkUser:Login": "Log in with this account", + "LinkAccountWarning": "Please note that you are linking to other accounts, Click here to cancel the link login!", + "LinkAccountWillBeCreateWarning": "You will log out from your current account and then log in with another account. After completing the login process, the two accounts will be linked together.", + "LinkAccountWillBeDeleteWarning": "Are you sure you want to delete the associated account \"{0}\"?", + "LinkLogged": "Accounts are linked", + "StayWithCurrentAccount": "Stay with the current account", + "Settings:Identity.Account": "Account" } } \ No newline at end of file diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json index 7325b8892..64de06182 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json @@ -17,6 +17,8 @@ "DisplayName:AuthenticatorCode": "验证代码", "DisplayName:PhoneNumber": "手机号码", "DisplayName:Code": "验证码", + "DisplayName:LinkUserName": "用户名", + "DisplayName:DirectlyLinked": "直接关联", "TwoFactor": "双因素身份验证", "TwoFactor:Enabled": "启用双因素认证", "TwoFactor:Email": "邮箱验证", @@ -67,6 +69,15 @@ "CancelBindWarningMessage": "解除绑定后将无法使用外部身份,如果你通过此方式登录,你的会话将被注销!", "EmailConfirm": "确认邮件", "AvatarChanged": "变更头像", - "ClickToValidation": "点击去验证" + "ClickToValidation": "点击去验证", + "LinkUser": "关联账户", + "LinkUser:New": "新关联账户", + "LinkUser:Login": "以该账号登录", + "LinkAccountWarning": "请注意,你正在关联到其他帐户,单击此处取消链接关联!", + "LinkAccountWillBeCreateWarning": "您将从当前账户退出,然后用另一个账户登录.完成登录后,两个账户将被关联起来.", + "LinkAccountWillBeDeleteWarning": "您确定要删除关联帐户\"{0}\"吗?", + "LinkLogged": "帐户已经关联", + "StayWithCurrentAccount": "继续使用当前帐户", + "Settings:Identity.Account": "用户账户" } } \ No newline at end of file diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/IdentityLinkUserAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/IdentityLinkUserAppService.cs new file mode 100644 index 000000000..34bc88cad --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/IdentityLinkUserAppService.cs @@ -0,0 +1,170 @@ +using LINGYUN.Abp.Account.Dto; +using Microsoft.AspNetCore.Authorization; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Identity; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.Account; + +[Authorize] +public class IdentityLinkUserAppService : AccountApplicationServiceBase, IIdentityLinkUserAppService +{ + protected IdentityLinkUserManager IdentityLinkUserManager { get; } + + protected ITenantStore TenantStore { get; } + + public IdentityLinkUserAppService( + IdentityLinkUserManager identityLinkUserManager, + ITenantStore tenantStore) + { + IdentityLinkUserManager = identityLinkUserManager; + TenantStore = tenantStore; + } + + public async virtual Task GenerateLinkLoginTokenAsync() + { + return await IdentityLinkUserManager.GenerateLinkTokenAsync( + new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), + LinkUserTokenProviderConsts.LinkUserLoginTokenPurpose); + } + + public async virtual Task GenerateLinkTokenAsync() + { + return await IdentityLinkUserManager.GenerateLinkTokenAsync( + new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), + LinkUserTokenProviderConsts.LinkUserTokenPurpose); + } + + public async virtual Task> GetListAsync() + { + var identityLinkUserDtos = new List(); + var identityLinkUserInfo = new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id); + var identityLinkUsers = await IdentityLinkUserManager.GetListAsync(identityLinkUserInfo, includeIndirect: true); + + var currentUserId = CurrentUser.GetId(); + var currentTenantId = CurrentTenant.Id; + + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); + var allIdentityLinkUserDtos = identityLinkUsers + .SelectMany(x => new[] + { + new LinkUserDto + { + LinkTenantId = x.TargetTenantId, + LinkUserId = x.TargetUserId, + DirectlyLinked = (x.SourceTenantId == currentTenantId && x.SourceUserId == currentUserId) + || (x.TargetTenantId == currentTenantId && x.TargetUserId == currentUserId) + }, + new LinkUserDto + { + LinkTenantId = x.SourceTenantId, + LinkUserId = x.SourceUserId, + DirectlyLinked = (x.SourceTenantId == currentTenantId && x.SourceUserId == currentUserId) + || (x.TargetTenantId == currentTenantId && x.TargetUserId == currentUserId) + } + }) + .Where(x => x.LinkTenantId != currentTenantId || x.LinkUserId != currentUserId) + .GroupBy(x => new { x.LinkTenantId, x.LinkUserId }) + .Select(g => g.FirstOrDefault(x => x.DirectlyLinked) ?? g.First()) + .ToList(); + + foreach (var identityLinkUserDto in allIdentityLinkUserDtos) + { + var linkTenant = allActiveTenants.FirstOrDefault(x => x.Id == identityLinkUserDto.LinkTenantId); + using (CurrentTenant.Change(linkTenant?.Id, linkTenant?.Name)) + { + var linkUser = await UserManager.FindByIdAsync(identityLinkUserDto.LinkUserId.ToString()); + if (linkUser != null) + { + identityLinkUserDto.LinkUserName = linkUser.UserName; + identityLinkUserDtos.Add( + new LinkUserDto + { + LinkTenantId = linkTenant?.Id, + LinkTenantName = linkTenant?.Name, + LinkUserId = linkUser.Id, + LinkUserName = linkUser.UserName, + DirectlyLinked = identityLinkUserDto.DirectlyLinked, + }); + } + } + } + + return new ListResultDto(identityLinkUserDtos); + } + + public async virtual Task LinkAsync(LinkUserInput input) + { + var identityLinkUserInfo = new IdentityLinkUserInfo(input.UserId, input.TenantId); + if (await IdentityLinkUserManager.VerifyLinkTokenAsync(identityLinkUserInfo, input.Token, LinkUserTokenProviderConsts.LinkUserTokenPurpose)) + { + await IdentityLinkUserManager.LinkAsync( + new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), + identityLinkUserInfo); + return; + } + + throw new BusinessException( + LINGYUN.Abp.Identity.IdentityErrorCodes.LinkUserTokenInValid, + "Link user token is invalid!"); + } + + public async virtual Task UnlinkAsync(UnLinkUserInput input) + { + await IdentityLinkUserManager.UnlinkAsync( + new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), + new IdentityLinkUserInfo(input.UserId, input.TenantId)); + } + + public async virtual Task VerifyLinkUserAsync(VerifyLinkUserInput input) + { + if (await IdentityLinkUserManager.IsLinkedAsync( + new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), + new IdentityLinkUserInfo(input.UserId, input.TenantId), + includeIndirect: true)) + { + using (CurrentTenant.Change(input.TenantId)) + { + TenantConfiguration tenant = null; + if (input.TenantId.HasValue) + { + tenant = await TenantStore.FindAsync(input.TenantId.Value); + } + var user = await UserManager.FindByIdAsync(input.UserId.ToString()); + + return new VerifyLinkUserDto + { + LinkTenantId = tenant?.Id, + LinkTenantName = tenant?.Name, + LinkUserId = user?.Id, + LinkUserName = user?.UserName, + IsLinked = user != null + }; + } + } + return new VerifyLinkUserDto { IsLinked = false }; + } + + [AllowAnonymous] + public async virtual Task VerifyLinkLoginTokenAsync(VerifyLinkTokenInput input) + { + return await IdentityLinkUserManager.VerifyLinkTokenAsync( + new IdentityLinkUserInfo(input.UserId, input.TenantId), + input.Token, + LinkUserTokenProviderConsts.LinkUserLoginTokenPurpose); + } + + [AllowAnonymous] + public async virtual Task VerifyLinkTokenAsync(VerifyLinkTokenInput input) + { + return await IdentityLinkUserManager.VerifyLinkTokenAsync( + new IdentityLinkUserInfo(input.UserId, input.TenantId), + input.Token, + LinkUserTokenProviderConsts.LinkUserTokenPurpose); + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs index 39b222546..2aab510c0 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs @@ -1,77 +1,77 @@ -using Microsoft.AspNetCore.Mvc; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Account; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Account; using Volo.Abp.Application.Dtos; -using Volo.Abp.AspNetCore.Mvc; - -namespace LINGYUN.Abp.Account; - -[RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] -[Area("account")] -[Route("api/account")] -public class AccountController : AbpControllerBase, IAccountAppService -{ - protected IAccountAppService AccountAppService { get; } - public AccountController( - IAccountAppService accountAppService) - { - AccountAppService = accountAppService; - } - - [HttpPost] - [Route("wechat/register")] - public async virtual Task RegisterAsync(WeChatRegisterDto input) - { - await AccountAppService.RegisterAsync(input); - } - - [HttpPost] - [Route("phone/register")] - public async virtual Task RegisterAsync(PhoneRegisterDto input) - { - await AccountAppService.RegisterAsync(input); - } - - [HttpPut] - [Route("phone/reset-password")] - public async virtual Task ResetPasswordAsync(PhoneResetPasswordDto input) - { - await AccountAppService.ResetPasswordAsync(input); - } - - [HttpPost] - [Route("phone/send-signin-code")] - public async virtual Task SendPhoneSigninCodeAsync(SendPhoneSigninCodeDto input) - { - await AccountAppService.SendPhoneSigninCodeAsync(input); - } - - [HttpPost] - [Route("email/send-signin-code")] +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.Account; + +[RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] +[Area("account")] +[Route("api/account")] +public class AccountController : AbpControllerBase, IAccountAppService +{ + protected IAccountAppService AccountAppService { get; } + public AccountController( + IAccountAppService accountAppService) + { + AccountAppService = accountAppService; + } + + [HttpPost] + [Route("wechat/register")] + public async virtual Task RegisterAsync(WeChatRegisterDto input) + { + await AccountAppService.RegisterAsync(input); + } + + [HttpPost] + [Route("phone/register")] + public async virtual Task RegisterAsync(PhoneRegisterDto input) + { + await AccountAppService.RegisterAsync(input); + } + + [HttpPut] + [Route("phone/reset-password")] + public async virtual Task ResetPasswordAsync(PhoneResetPasswordDto input) + { + await AccountAppService.ResetPasswordAsync(input); + } + + [HttpPost] + [Route("phone/send-signin-code")] + public async virtual Task SendPhoneSigninCodeAsync(SendPhoneSigninCodeDto input) + { + await AccountAppService.SendPhoneSigninCodeAsync(input); + } + + [HttpPost] + [Route("email/send-signin-code")] public async virtual Task SendEmailSigninCodeAsync(SendEmailSigninCodeDto input) { await AccountAppService.SendEmailSigninCodeAsync(input); - } - - [HttpPost] - [Route("phone/send-register-code")] - public async virtual Task SendPhoneRegisterCodeAsync(SendPhoneRegisterCodeDto input) - { - await AccountAppService.SendPhoneRegisterCodeAsync(input); - } - - [HttpPost] - [Route("phone/send-password-reset-code")] - public async virtual Task SendPhoneResetPasswordCodeAsync(SendPhoneResetPasswordCodeDto input) - { - await AccountAppService.SendPhoneResetPasswordCodeAsync(input); - } - - [HttpGet] - [Route("two-factor-providers")] + } + + [HttpPost] + [Route("phone/send-register-code")] + public async virtual Task SendPhoneRegisterCodeAsync(SendPhoneRegisterCodeDto input) + { + await AccountAppService.SendPhoneRegisterCodeAsync(input); + } + + [HttpPost] + [Route("phone/send-password-reset-code")] + public async virtual Task SendPhoneResetPasswordCodeAsync(SendPhoneResetPasswordCodeDto input) + { + await AccountAppService.SendPhoneResetPasswordCodeAsync(input); + } + + [HttpGet] + [Route("two-factor-providers")] public async virtual Task> GetTwoFactorProvidersAsync(GetTwoFactorProvidersInput input) { return await AccountAppService.GetTwoFactorProvidersAsync(input); - } -} + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/IdentityLinkUserController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/IdentityLinkUserController.cs new file mode 100644 index 000000000..9f05614e5 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/IdentityLinkUserController.cs @@ -0,0 +1,70 @@ +using LINGYUN.Abp.Account.Dto; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Account; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.Account; + +[RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] +[Area("account")] +[Route("api/account/link-users")] +public class IdentityLinkUserController(IIdentityLinkUserAppService _service) : AbpControllerBase, IIdentityLinkUserAppService +{ + [HttpPost] + [Route("generate-link-login-token")] + public virtual Task GenerateLinkLoginTokenAsync() + { + return _service.GenerateLinkLoginTokenAsync(); + } + + [HttpPost] + [Route("generate-link-token")] + public virtual Task GenerateLinkTokenAsync() + { + return _service.GenerateLinkTokenAsync(); + } + + [HttpGet] + public virtual Task> GetListAsync() + { + return _service.GetListAsync(); + } + + [HttpPost] + [Route("link")] + public virtual Task LinkAsync(LinkUserInput input) + { + return _service.LinkAsync(input); + } + + [HttpPost] + [Route("unlink")] + public virtual Task UnlinkAsync(UnLinkUserInput input) + { + return _service.UnlinkAsync(input); + } + + [HttpPost] + [Route("verify-link-user")] + public virtual Task VerifyLinkUserAsync(VerifyLinkUserInput input) + { + return _service.VerifyLinkUserAsync(input); + } + + [HttpPost] + [Route("verify-link-login-token")] + public virtual Task VerifyLinkLoginTokenAsync(VerifyLinkTokenInput input) + { + return _service.VerifyLinkLoginTokenAsync(input); + } + + [HttpPost] + [Route("verify-link-token")] + public virtual Task VerifyLinkTokenAsync(VerifyLinkTokenInput input) + { + return _service.VerifyLinkTokenAsync(input); + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Controllers/AuthorizeController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Controllers/AuthorizeController.cs index 903bf8f9b..d18dfbe92 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Controllers/AuthorizeController.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Controllers/AuthorizeController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; using OpenIddict.Abstractions; using OpenIddict.Server.AspNetCore; using System; @@ -46,9 +47,26 @@ public class AuthorizeController : Volo.Abp.OpenIddict.Controllers.AuthorizeCont // // For scenarios where the default authentication handler configured in the ASP.NET Core // authentication options shouldn't be used, a specific scheme can be specified here. + if (request.HasPromptValue(OpenIddictConstants.PromptValues.Login)) + { + var prompt = string.Join(" ", request.GetPromptValues().Remove(OpenIddictConstants.PromptValues.Login)); + + var parameters = Request.HasFormContentType ? + Request.Form.Where(parameter => parameter.Key != OpenIddictConstants.Parameters.Prompt).ToList() : + Request.Query.Where(parameter => parameter.Key != OpenIddictConstants.Parameters.Prompt).ToList(); + + parameters.Add(KeyValuePair.Create(OpenIddictConstants.Parameters.Prompt, new StringValues(prompt))); + + return Challenge( + authenticationSchemes: IdentityConstants.ApplicationScheme, + properties: new AuthenticationProperties() + { + RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters) + }); + } var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme); if (result is not { Succeeded: true } || - ((request.HasPromptValue(OpenIddictConstants.PromptValues.Login) || request.MaxAge is 0 || + ((request.MaxAge is 0 || (request.MaxAge is not null && result.Properties?.IssuedUtc is not null && TimeProvider.System.GetUtcNow() - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value))) && TempData["IgnoreAuthenticationChallenge"] is null or false)) diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Pages/Account/SelectAccount.cshtml.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Pages/Account/SelectAccount.cshtml.cs index 43a8490cd..7340a7219 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Pages/Account/SelectAccount.cshtml.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web.OpenIddict/Pages/Account/SelectAccount.cshtml.cs @@ -233,7 +233,7 @@ public class SelectAccountModel : AccountPageModel if (RedirectUri.StartsWith("/")) { - int queryIndex = RedirectUri.IndexOf('?'); + var queryIndex = RedirectUri.IndexOf('?'); if (queryIndex >= 0) { queryString = RedirectUri.Substring(queryIndex + 1); diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml new file mode 100644 index 000000000..943d86377 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml @@ -0,0 +1,26 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization; +@using Volo.Abp.Account.Localization; +@using Volo.Abp.MultiTenancy; +@using Volo.Abp.Users; +@model LINGYUN.Abp.Account.Web.Pages.Account.LinkLoggedModel +@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout +@inject IHtmlLocalizer L +@inject ICurrentUser CurrentUser +@inject ICurrentTenant CurrentTenant +@{ + PageLayout.Content.Title = L["LinkLogged"].Value; +} + +
+ +
+ + +
+ @L["LogInUsingYourProviderAccount", Model.LinkTenantAndUserName] → +
+
+
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml.cs new file mode 100644 index 000000000..47a5649ec --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/LinkLogged.cshtml.cs @@ -0,0 +1,106 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp.Account.Web.Pages.Account; +using Volo.Abp.Identity; +using Volo.Abp.Security.Claims; + +namespace LINGYUN.Abp.Account.Web.Pages.Account; + +[Authorize] +public class LinkLoggedModel : AccountPageModel +{ + [BindProperty(SupportsGet = true)] + public string ReturnUrl { get; set; } + + [BindProperty(SupportsGet = true)] + public string ReturnUrlHash { get; set; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid LinkUserId { get; set; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid? LinkTenantId { get; set; } + + public string LinkTenantAndUserName { get; set; } + + protected ICurrentPrincipalAccessor CurrentPrincipalAccessor => LazyServiceProvider.LazyGetRequiredService(); + public IIdentityLinkUserAppService IdentityLinkUserAppService => LazyServiceProvider.LazyGetRequiredService(); + public IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache => LazyServiceProvider.LazyGetRequiredService(); + + public virtual async Task OnGetAsync() + { + var validLinkUser = await IdentityLinkUserAppService.VerifyLinkUserAsync( + new Dto.VerifyLinkUserInput + { + UserId = LinkUserId, + TenantId = LinkTenantId, + }); + if (!validLinkUser.IsLinked) + { + return await RedirectToLoginPageAsync(); + } + LinkTenantAndUserName = !validLinkUser.LinkTenantName.IsNullOrWhiteSpace() + ? $"{validLinkUser.LinkTenantName}\\{validLinkUser.LinkUserName}" + : validLinkUser.LinkUserName; + + return Page(); + } + + public async virtual Task OnPostAsync() + { + if (LinkUserId == CurrentUser.Id && LinkTenantId == CurrentTenant.Id) + { + return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash); + } + + using (CurrentTenant.Change(LinkTenantId)) + { + var sourceUser = await UserManager.GetByIdAsync(LinkUserId); + using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(sourceUser))) + { + var validLinkUser = await IdentityLinkUserAppService.VerifyLinkUserAsync( + new Dto.VerifyLinkUserInput + { + UserId = LinkUserId, + TenantId = LinkTenantId, + }); + if (validLinkUser.IsLinked) + { + var isPersistent = (await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme))?.Properties?.IsPersistent ?? false; + await SignInManager.SignOutAsync(); + using (CurrentTenant.Change(LinkTenantId)) + { + var targetUser = await UserManager.GetByIdAsync(LinkUserId); + await SignInManager.SignInAsync(targetUser, isPersistent); + await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(targetUser.Id, targetUser.TenantId); + } + + return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash); + } + } + } + + Alerts.Warning(L["Volo.Abp.Identity:InvalidToken"]); + return Page(); + } + + public virtual Task GetReturnUrlAsync(string returnUrl, string returnUrlHash) + { + return base.GetRedirectUrlAsync(returnUrl, returnUrlHash); + } + + protected virtual Task RedirectToLoginPageAsync() + { + return Task.FromResult(RedirectToPage("./Login", new + { + ReturnUrl, + ReturnUrlHash + })); + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml index 0cd0de615..dac94f917 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml @@ -24,13 +24,23 @@ }
public const string PasswordInHistoryInValid = "Volo.Abp.Identity:020013"; + /// + /// 关联用户Token无效 + /// + public const string LinkUserTokenInValid = "Volo.Abp.Identity:020014"; } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json index 82450d78d..80d38aba9 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json @@ -54,6 +54,7 @@ "Volo.Abp.Identity:020011": "Secondary authentication cannot be enabled when an MFA device is not attached!", "Volo.Abp.Identity:020012": "Invalid authenticator code!", "Volo.Abp.Identity:020013": "The password cannot be the same as the previous one.!", + "Volo.Abp.Identity:020014": "Link user token is invalid!", "Volo.Abp.Identity:DuplicatePhoneNumber": "Phone number '{0}' is already taken.", "DisplayName:Abp.Identity.User.SmsNewUserRegister": "Register sms template", "Description:Abp.Identity.User.SmsNewUserRegister": "When the user registers, he/she should send the template number of the SMS verification code and fill in the template number of the corresponding cloud platform registration", diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json index 4187cf83c..2dfb6959b 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json @@ -54,6 +54,7 @@ "Volo.Abp.Identity:020011": "未绑定MFA设备时无法启用二次认证!", "Volo.Abp.Identity:020012": "无效的验证器代码!", "Volo.Abp.Identity:020013": "密码不能与之前的密码相同!", + "Volo.Abp.Identity:020014": "关联用户Token无效!", "Volo.Abp.Identity:DuplicatePhoneNumber": "手机号 '{0}' 已存在.", "DisplayName:Abp.Identity.User.SmsNewUserRegister": "新用户注册模板", "Description:Abp.Identity.User.SmsNewUserRegister": "新用户通过手机注册账号验证码模板", diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/AbpOpenIddictLinkUserModule.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/AbpOpenIddictLinkUserModule.cs index 90f711b1a..cc26f27c9 100644 --- a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/AbpOpenIddictLinkUserModule.cs +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/AbpOpenIddictLinkUserModule.cs @@ -17,6 +17,7 @@ public class AbpOpenIddictLinkUserModule : AbpModule PreConfigure(builder => { builder.AllowLinkUserFlow(); + builder.AddEventHandler(LinkUserAuthorizationHandler.Descriptor); }); } diff --git a/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/LinkUserAuthorizationHandler.cs b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/LinkUserAuthorizationHandler.cs new file mode 100644 index 000000000..20e07745a --- /dev/null +++ b/aspnet-core/modules/openIddict/LINGYUN.Abp.OpenIddict.LinkUser/LINGYUN/Abp/OpenIddict/LinkUser/LinkUserAuthorizationHandler.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore; +using OpenIddict.Server; +using System.Linq; +using System.Threading.Tasks; +using static OpenIddict.Server.OpenIddictServerEvents; + +namespace LINGYUN.Abp.OpenIddict.LinkUser; + +public class LinkUserAuthorizationHandler : IOpenIddictServerHandler +{ + public static OpenIddictServerHandlerDescriptor Descriptor { get; } + = OpenIddictServerHandlerDescriptor.CreateBuilder() + .UseScopedHandler() + .SetOrder(2000) + .SetType(OpenIddictServerHandlerType.Custom) + .Build(); + + public async ValueTask HandleAsync(ValidateAuthorizationRequestContext context) + { + var request = context.Transaction.GetHttpRequest(); + if (request == null) + { + return; + } + + var linkUserId = request.Query["LinkUserId"].FirstOrDefault(); + var linkToken = request.Query["LinkToken"].FirstOrDefault(); + + if (string.IsNullOrEmpty(linkUserId) || string.IsNullOrEmpty(linkToken)) + { + return; + } + + context.Transaction.SetProperty("LinkUserId", linkUserId); + context.Transaction.SetProperty("LinkToken", linkToken); + } +} From d9ebbd68ac8e1a6ddc268efe1daeb1c1f9c09e04 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 13:42:38 +0800 Subject: [PATCH 29/40] fix: Fix the link for logging in with the current account --- .../Pages/Account/Login.cshtml | 2 +- .../Pages/Account/Login.cshtml.cs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml index dac94f917..a44496f59 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml @@ -27,7 +27,7 @@ @if (Model.IsLinkLogin) { - @L["LinkAccountWarning", Url.PageLink()] + @L["LinkAccountWarning", await Model.GetWithoutLinkReturnUrlAsync(Model.ReturnUrl, Model.ReturnUrlHash)] } diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 4f338a9d0..8ab17a456 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -19,6 +19,7 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Linq; using System.Security.Claims; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Account.Settings; @@ -668,7 +669,21 @@ public class LoginModel : AccountPageModel #region LinkUser - protected virtual async Task VerifyLinkTokenAsync() + public async virtual Task GetWithoutLinkReturnUrlAsync(string returnUrl, string returnUrlHash) + { + var redirectUrl = await base.GetRedirectUrlAsync(returnUrl, returnUrlHash); + + // ʹÓÃÕýÔò±í´ïʽÒƳý LinkUser ²ÎÊý + redirectUrl = Regex.Replace(redirectUrl, @"[&?]LinkToken=[^&]*", ""); + redirectUrl = Regex.Replace(redirectUrl, @"[&?]LinkUserId=[^&]*", ""); + redirectUrl = Regex.Replace(redirectUrl, @"[&?]LinkTenantId=[^&]*", ""); + redirectUrl = Regex.Replace(redirectUrl, @"[&?]linkUserId=[^&]*", ""); + redirectUrl = Regex.Replace(redirectUrl, @"[&?]linkToken=[^&]*", ""); + + return redirectUrl; + } + + protected async virtual Task VerifyLinkTokenAsync() { if (LinkToken.IsNullOrWhiteSpace() || !LinkUserId.HasValue) { From 3d75cdcf4ba8cfaf23950dc6fcc7e99a6009c7cb Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 14:45:55 +0800 Subject: [PATCH 30/40] feat(settings): Enhancement settings definition --- .../AliyunSettingAppService.cs | 2 +- .../LINGYUN.Abp.Aliyun.csproj | 1 + .../Aliyun/Settings/AliyunSettingProvider.cs | 134 ++++++-- .../Abp/Tencent/QQ/Localization/en.json | 3 +- .../Abp/Tencent/QQ/Localization/zh-Hans.json | 3 +- .../TencentQQSettingDefinitionProvider.cs | 18 +- .../TencentCloudSettingAppService.cs | 2 +- .../LINGYUN.Abp.Tencent.csproj | 4 + .../Tencent/Localization/Resources/en.json | 6 +- .../Localization/Resources/zh-Hans.json | 6 +- .../TencentCloudSettingDefinitionProvider.cs | 68 +++- .../Settings/TencentCloudSettingNames.cs | 39 +++ ...ingManagement.Application.Contracts.csproj | 4 + .../Dto/SettingDetailsDto.cs | 1 + .../Abp/SettingManagement/Dto/SettingDto.cs | 1 + .../IReadonlySettingV2AppService.cs | 9 + .../SettingManagement/ISettingV2AppService.cs | 8 + .../IUserSettingV2AppService.cs | 11 + .../LINGYUN.Abp.Settings.csproj | 1 + .../Settings/ISettingProviderExtensions.cs | 2 +- .../Settings/SettingDefinitionExtensions.cs | 314 ++++++++++++++++++ .../Abp/Settings/SettingResourceDefinition.cs | 119 +++++++ .../Volo/Abp/Settings}/ValueType.cs | 2 +- .../Localization/Resources/en.json | 3 +- .../Localization/Resources/zh-Hans.json | 3 +- ...hatMiniProgramSettingDefinitionProvider.cs | 34 +- .../Official/Localization/Resources/en.json | 3 +- .../Localization/Resources/zh-Hans.json | 3 +- ...WeChatOfficialSettingDefinitionProvider.cs | 51 ++- .../Contacts/Localization/Resources/en.json | 3 +- .../Localization/Resources/zh-Hans.json | 3 +- ...hatWorkContactSettingDefinitionProvider.cs | 16 +- .../Localization/Resources/en.json | 3 +- .../Localization/Resources/zh-Hans.json | 3 +- ...xternalContactSettingDefinitionProvider.cs | 16 +- .../LINGYUN.Abp.WeChat.Work.csproj | 1 + .../Work/Localization/Resources/en.json | 5 +- .../Work/Localization/Resources/zh-Hans.json | 5 +- .../WeChatWorkSettingDefinitionProvider.cs | 53 ++- .../LINGYUN.Abp.WeChat.csproj | 1 + .../Abp/WeChat/Localization/Resources/en.json | 4 +- .../Localization/Resources/zh-Hans.json | 4 +- .../WeChatSettingDefinitionProvider.cs | 8 +- .../AccountGroupSettingDefinitionProvider.cs | 31 ++ .../LINGYUN.Abp.Account.OAuth.csproj | 4 + .../AccountOAuthSettingDefinitionProvider.cs | 27 +- .../Localization/Resources/en.json | 4 +- .../Localization/Resources/zh-Hans.json | 4 +- .../LINGYUN.Abp.AIManagement.Domain.csproj | 1 + .../AIManagementSettingDefinitionProvider.cs | 14 +- ...mentPermissionSettingDefinitionProvider.cs | 18 + ...UN.Abp.BlobManagement.Domain.Shared.csproj | 4 + .../Localization/Resources/en.json | 4 +- .../Localization/Resources/zh-Hans.json | 4 +- ...BlobManagementSettingDefinitionProvider.cs | 29 +- .../BlobManagementSettingAppService.cs | 2 +- .../LINGYUN.Abp.Identity.Domain.Shared.csproj | 4 + .../LINGYUN/Abp/Identity/Localization/en.json | 10 +- .../Abp/Identity/Localization/zh-Hans.json | 10 +- .../IdentitySettingDefinitionProvider.cs | 67 +++- .../LINGYUN.Abp.Identity.Domain.csproj | 1 + .../IdentityGroupSettingDefinitionProvider.cs | 247 ++++++++++++++ ...UN.Abp.MessageService.Domain.Shared.csproj | 1 + .../Localization/Resources/en.json | 6 +- .../Localization/Resources/zh-Hans.json | 6 +- ...MessageServiceSettingDefinitionProvider.cs | 6 +- .../WebhookNotificationPublishProvider.cs | 23 +- ...N.Abp.SettingManagement.Application.csproj | 1 + .../AbpSettingManagementApplicationModule.cs | 5 + .../Localization/Resources/en.json | 10 +- .../Localization/Resources/zh-Hans.json | 10 +- .../SettingManagement/SettingV2AppService.cs | 62 ++++ .../SettingV2AppServiceBase.cs | 165 +++++++++ .../UserSettingV2AppService.cs | 38 +++ .../SettingManagement/SettingController.cs | 106 +++--- .../SettingManagement/SettingV2Controller.cs | 26 ++ .../UserSettingV2Controller.cs | 26 ++ 77 files changed, 1782 insertions(+), 174 deletions(-) create mode 100644 aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IReadonlySettingV2AppService.cs create mode 100644 aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/ISettingV2AppService.cs create mode 100644 aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IUserSettingV2AppService.cs create mode 100644 aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs create mode 100644 aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingResourceDefinition.cs rename aspnet-core/framework/settings/{LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto => LINGYUN.Abp.Settings/Volo/Abp/Settings}/ValueType.cs (93%) create mode 100644 aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountGroupSettingDefinitionProvider.cs create mode 100644 aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobManagementPermissionSettingDefinitionProvider.cs create mode 100644 aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityGroupSettingDefinitionProvider.cs create mode 100644 aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppService.cs create mode 100644 aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppServiceBase.cs create mode 100644 aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/UserSettingV2AppService.cs create mode 100644 aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingV2Controller.cs create mode 100644 aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/UserSettingV2Controller.cs diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun.SettingManagement/LINGYUN/Abp/Aliyun/SettingManagement/AliyunSettingAppService.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun.SettingManagement/LINGYUN/Abp/Aliyun/SettingManagement/AliyunSettingAppService.cs index 08ddb96d7..12fadff37 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun.SettingManagement/LINGYUN/Abp/Aliyun/SettingManagement/AliyunSettingAppService.cs +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun.SettingManagement/LINGYUN/Abp/Aliyun/SettingManagement/AliyunSettingAppService.cs @@ -9,7 +9,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.MultiTenancy; using Volo.Abp.SettingManagement; using Volo.Abp.Settings; -using ValueType = LINGYUN.Abp.SettingManagement.ValueType; +using ValueType = Volo.Abp.Settings.ValueType; namespace LINGYUN.Abp.Aliyun.SettingManagement; diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj index fd6b3232a..317bed293 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj @@ -35,6 +35,7 @@ + diff --git a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs index 955594a6a..ce6473eb9 100644 --- a/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs +++ b/aspnet-core/framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN/Abp/Aliyun/Settings/AliyunSettingProvider.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.Aliyun.Localization; +using LINGYUN.Abp.Aliyun.Features; +using LINGYUN.Abp.Aliyun.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,8 @@ namespace LINGYUN.Abp.Aliyun.Settings; public class AliyunSettingProvider : SettingDefinitionProvider { + private const string GroupName = "Aliyun"; + public override void Define(ISettingDefinitionContext context) { context.Add(GetAuthorizationSettings()); @@ -28,7 +31,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")), new SettingDefinition( AliyunSettingNames.Authorization.AccessKeySecret, displayName: L("DisplayName:AccessKeySecret"), @@ -40,7 +48,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")), new SettingDefinition( AliyunSettingNames.Authorization.DurationSeconds, defaultValue: "3600", @@ -52,7 +65,13 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")) + .WithValueType(ValueType.Number), new SettingDefinition( AliyunSettingNames.Authorization.Policy, displayName: L("DisplayName:Policy"), @@ -64,7 +83,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")), new SettingDefinition( AliyunSettingNames.Authorization.RamRoleArn, displayName: L("DisplayName:RamRoleArn"), @@ -76,7 +100,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")), new SettingDefinition( AliyunSettingNames.Authorization.RegionId, defaultValue: "cn-hangzhou", @@ -88,7 +117,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")), new SettingDefinition( AliyunSettingNames.Authorization.RoleSessionName, displayName: L("DisplayName:RoleSessionName"), @@ -100,7 +134,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")), new SettingDefinition( AliyunSettingNames.Authorization.UseSecurityTokenService, defaultValue: true.ToString(), @@ -112,7 +151,13 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Enable]) + .WithParent("RAM", L("DisplayName:Aliyun.RAM")) + .WithValueType(ValueType.Boolean), }; } @@ -131,7 +176,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")), new SettingDefinition( AliyunSettingNames.Sms.DefaultSignName, displayName: L("DisplayName:DefaultSignName"), @@ -143,7 +193,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")), new SettingDefinition( AliyunSettingNames.Sms.DefaultTemplateCode, displayName: L("DisplayName:DefaultTemplateCode"), @@ -155,7 +210,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")), new SettingDefinition( AliyunSettingNames.Sms.DefaultPhoneNumber, displayName: L("DisplayName:DefaultPhoneNumber"), @@ -166,7 +226,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")), new SettingDefinition( AliyunSettingNames.Sms.Domain, defaultValue: "dysmsapi.aliyuncs.com", @@ -178,7 +243,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")), new SettingDefinition( AliyunSettingNames.Sms.Version, defaultValue: "2017-05-25", @@ -190,7 +260,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")), new SettingDefinition( AliyunSettingNames.Sms.VisableErrorToClient, defaultValue: false.ToString(), @@ -203,6 +278,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("Sms", L("DisplayName:Aliyun.Sms")) + .WithValueType(ValueType.Boolean) }; } @@ -221,7 +302,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("SmsVerifyCode", L("DisplayName:Aliyun.SmsVerifyCode")), new SettingDefinition( AliyunSettingNames.SmsVerifyCode.DefaultSignName, displayName: L("DisplayName:DefaultSignName"), @@ -233,7 +319,12 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("SmsVerifyCode", L("DisplayName:Aliyun.SmsVerifyCode")), new SettingDefinition( AliyunSettingNames.SmsVerifyCode.DefaultTemplateCode, displayName: L("DisplayName:DefaultTemplateCode"), @@ -245,10 +336,15 @@ public class AliyunSettingProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("DisplayName:Aliyun"), + requiredFeatures: [AliyunFeatureNames.Sms.Enable]) + .WithParent("SmsVerifyCode", L("DisplayName:Aliyun.SmsVerifyCode")), }; } - private ILocalizableString L(string name) + private LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/en.json b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/en.json index d60c9bc60..db8f61c9b 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/en.json +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/en.json @@ -11,6 +11,7 @@ "DisplayName:QQConnect.AppKey": "AppKey", "Description:QQConnect.AppKey": "When accessing user resources, it is used to verify the validity of the application and apply for it in QQ Interconnection Management Center.", "DisplayName:QQConnect.IsMobile": "Whether to move the style", - "Description:QQConnect.IsMobile": "The style used for display is displayed as the style under PC by default." + "Description:QQConnect.IsMobile": "The style used for display is displayed as the style under PC by default.", + "Settings:TenantCloud.QQConnect": "QQ Connect" } } \ No newline at end of file diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/zh-Hans.json b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/zh-Hans.json index 6387384f3..00406dfc2 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/zh-Hans.json +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Localization/zh-Hans.json @@ -11,6 +11,7 @@ "DisplayName:QQConnect.AppKey": "AppId对应的密钥", "Description:QQConnect.AppKey": "访问用户资源时用来验证应用的合法性, 在QQ互联管理中心申请.", "DisplayName:QQConnect.IsMobile": "是否移动端样式", - "Description:QQConnect.IsMobile": "用于展示的样式, 默认展示为PC下的样式." + "Description:QQConnect.IsMobile": "用于展示的样式, 默认展示为PC下的样式.", + "Settings:TenantCloud.QQConnect": "QQ互联" } } \ No newline at end of file diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Settings/TencentQQSettingDefinitionProvider.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Settings/TencentQQSettingDefinitionProvider.cs index e66c6d8b8..180896dae 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Settings/TencentQQSettingDefinitionProvider.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.QQ/LINGYUN/Abp/Tencent/QQ/Settings/TencentQQSettingDefinitionProvider.cs @@ -6,6 +6,8 @@ namespace LINGYUN.Abp.Tencent.QQ.Settings; public class TencentQQSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "TenantCloud"; + public override void Define(ISettingDefinitionContext context) { context.Add(GetQQConnectSettings()); @@ -25,7 +27,10 @@ public class TencentQQSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("QQConnect", L("Settings:TenantCloud.QQConnect"), order: 10) + .WithOrder(0), new SettingDefinition( TencentQQSettingNames.QQConnect.AppKey, displayName: L("DisplayName:QQConnect.AppKey"), @@ -36,7 +41,10 @@ public class TencentQQSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("QQConnect", L("Settings:TenantCloud.QQConnect"), order: 10) + .WithOrder(1), new SettingDefinition( TencentQQSettingNames.QQConnect.IsMobile, "false", @@ -49,10 +57,14 @@ public class TencentQQSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("QQConnect", L("Settings:TenantCloud.QQConnect"), order: 10) + .WithOrder(2) + .WithValueType(ValueType.Boolean) }; } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.SettingManagement/LINGYUN/Abp/Tencent/SettingManagement/TencentCloudSettingAppService.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.SettingManagement/LINGYUN/Abp/Tencent/SettingManagement/TencentCloudSettingAppService.cs index 71cf1ee4d..2cb8616aa 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.SettingManagement/LINGYUN/Abp/Tencent/SettingManagement/TencentCloudSettingAppService.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent.SettingManagement/LINGYUN/Abp/Tencent/SettingManagement/TencentCloudSettingAppService.cs @@ -10,7 +10,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.MultiTenancy; using Volo.Abp.SettingManagement; using Volo.Abp.Settings; -using ValueType = LINGYUN.Abp.SettingManagement.ValueType; +using ValueType = Volo.Abp.Settings.ValueType; namespace LINGYUN.Abp.Tencent.SettingManagement; diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN.Abp.Tencent.csproj b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN.Abp.Tencent.csproj index e03c07cfa..976c4de5f 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN.Abp.Tencent.csproj +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN.Abp.Tencent.csproj @@ -31,4 +31,8 @@ + + + + diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/en.json b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/en.json index 5f97f9c43..736a5cb07 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/en.json +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/en.json @@ -57,6 +57,10 @@ "Region:Moscow": "Europe (Moscow)", "Region:Virginia": "Eastern US (Virginia)", "Region:SiliconValley": "Western US (Silicon Valley)", - "Region:Toronto": "North America (Toronto)" + "Region:Toronto": "North America (Toronto)", + "Settings:TenantCloud": "Tenant Cloud", + "Settings:TenantCloud.ConnectionSetting": "Connection", + "Settings:TenantCloud.SmsSetting": "Sms", + "Settings:TenantCloud.BasicSetting": "Basic" } } \ No newline at end of file diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/zh-Hans.json b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/zh-Hans.json index cf0248289..56af3d15d 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Localization/Resources/zh-Hans.json @@ -57,6 +57,10 @@ "Region:Moscow": "欧洲地区(莫斯科)", "Region:Virginia": "美国东部(弗吉尼亚)", "Region:SiliconValley": "美国西部(硅谷)", - "Region:Toronto": "北美地区(多伦多)" + "Region:Toronto": "北美地区(多伦多)", + "Settings:TenantCloud": "腾讯云服务", + "Settings:TenantCloud.ConnectionSetting": "连接配置", + "Settings:TenantCloud.SmsSetting": "短信配置", + "Settings:TenantCloud.BasicSetting": "基础配置" } } \ No newline at end of file diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingDefinitionProvider.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingDefinitionProvider.cs index 6f42d1828..f84acd5e0 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingDefinitionProvider.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingDefinitionProvider.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.Tencent.Localization; +using LINGYUN.Abp.Tencent.Features; +using LINGYUN.Abp.Tencent.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,8 @@ namespace LINGYUN.Abp.Tencent.Settings; public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "TenantCloud"; + public override void Define(ISettingDefinitionContext context) { context.Add(GetBasicSettings()); @@ -29,7 +32,10 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("ConnectionSetting", L("Settings:TenantCloud.ConnectionSetting"), order: 0) + .WithOrder(0), new SettingDefinition( TencentCloudSettingNames.Connection.Timeout, // 默认 60秒 @@ -42,7 +48,11 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("ConnectionSetting", L("Settings:TenantCloud.ConnectionSetting"), order: 0) + .WithOrder(1) + .WithValueType(ValueType.Number), new SettingDefinition( TencentCloudSettingNames.Connection.WebProxy, displayName: L("DisplayName:WebProxy"), @@ -53,7 +63,10 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("ConnectionSetting", L("Settings:TenantCloud.ConnectionSetting"), order: 0) + .WithOrder(2), }; } @@ -72,7 +85,13 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:TenantCloud"), + requiredFeatures: [TencentCloudFeatures.Sms.Enable]) + .WithParent("SmsSetting", L("DisplayName:TenantCloud.SmsSetting"), order: 2) + .WithOrder(0), new SettingDefinition( TencentCloudSettingNames.Sms.DefaultSignName, displayName: L("DisplayName:DefaultSignName"), @@ -84,7 +103,13 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:TenantCloud"), + requiredFeatures: [TencentCloudFeatures.Sms.Enable]) + .WithParent("SmsSetting", L("DisplayName:TenantCloud.SmsSetting"), order: 2) + .WithOrder(1), new SettingDefinition( TencentCloudSettingNames.Sms.DefaultTemplateId, displayName: L("DisplayName:DefaultTemplateId"), @@ -96,7 +121,13 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:TenantCloud"), + requiredFeatures: [TencentCloudFeatures.Sms.Enable]) + .WithParent("SmsSetting", L("DisplayName:TenantCloud.SmsSetting"), order: 2) + .WithOrder(2), }; } @@ -116,7 +147,10 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("BasicSetting", L("DisplayName:TenantCloud.BasicSetting"), order: 1) + .WithOrder(0), new SettingDefinition( TencentCloudSettingNames.SecretId, displayName: L("DisplayName:SecretId"), @@ -128,7 +162,10 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("BasicSetting", L("DisplayName:TenantCloud.BasicSetting"), order: 1) + .WithOrder(1), new SettingDefinition( TencentCloudSettingNames.SecretKey, displayName: L("DisplayName:SecretKey"), @@ -140,7 +177,10 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("BasicSetting", L("DisplayName:TenantCloud.BasicSetting"), order: 1) + .WithOrder(2), new SettingDefinition( TencentCloudSettingNames.DurationSecond, defaultValue: "600", @@ -152,11 +192,15 @@ public class TencentCloudSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:TenantCloud")) + .WithParent("BasicSetting", L("DisplayName:TenantCloud.BasicSetting"), order: 1) + .WithOrder(3) + .WithValueType(ValueType.Number), }; } - private ILocalizableString L(string name) + private LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingNames.cs b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingNames.cs index 65bd9aaa5..76925d1e8 100644 --- a/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingNames.cs +++ b/aspnet-core/framework/cloud-tencent/LINGYUN.Abp.Tencent/LINGYUN/Abp/Tencent/Settings/TencentCloudSettingNames.cs @@ -20,6 +20,45 @@ public static class TencentCloudSettingNames ///
public const string DurationSecond = Prefix + ".DurationSecond"; /// + /// 认证方式 + /// + public class Authorization + { + public const string Prefix = TencentCloudSettingNames.Prefix + ".Authorization"; + /// + /// 地域ID + /// + public const string RegionId = Prefix + ".RegionId"; + /// + /// RAM账号的AccessKey ID + /// + public const string AccessKeyId = Prefix + ".AccessKeyId"; + /// + /// RAM账号的AccessKey Secret + /// + public const string AccessKeySecret = Prefix + ".AccessKeySecret"; + /// + /// 使用STS Token访问 + /// + public const string UseSecurityTokenService = Prefix + ".UseSecurityTokenService"; + /// + /// 使用RAM子账号的AssumeRole方式访问 + /// + public const string RamRoleArn = Prefix + ".RamRoleArn"; + /// + /// 用户自定义参数。此参数用来区分不同的令牌,可用于用户级别的访问审计 + /// + public const string RoleSessionName = Prefix + ".RoleSessionName"; + /// + /// 过期时间,单位为秒。 + /// + public const string DurationSeconds = Prefix + ".DurationSeconds"; + /// + /// 权限策略。 + /// + public const string Policy = Prefix + ".Policy"; + } + /// /// 连接设置 /// public class Connection diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN.Abp.SettingManagement.Application.Contracts.csproj b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN.Abp.SettingManagement.Application.Contracts.csproj index 377922e24..11dc914ef 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN.Abp.SettingManagement.Application.Contracts.csproj +++ b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN.Abp.SettingManagement.Application.Contracts.csproj @@ -26,4 +26,8 @@ + + + +
diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDetailsDto.cs b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDetailsDto.cs index 1c488302d..b7a6fe1f9 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDetailsDto.cs +++ b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDetailsDto.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using Volo.Abp.Settings; namespace LINGYUN.Abp.SettingManagement; diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDto.cs b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDto.cs index 7288598a3..4ad3b84b4 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDto.cs +++ b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/SettingDto.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using Volo.Abp.Settings; +using ValueType = Volo.Abp.Settings.ValueType; namespace LINGYUN.Abp.SettingManagement; diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IReadonlySettingV2AppService.cs b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IReadonlySettingV2AppService.cs new file mode 100644 index 000000000..1eac33166 --- /dev/null +++ b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IReadonlySettingV2AppService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.SettingManagement; + +public interface IReadonlySettingV2AppService : IApplicationService +{ + Task GetAsync(); +} diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/ISettingV2AppService.cs b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/ISettingV2AppService.cs new file mode 100644 index 000000000..c73f91d3c --- /dev/null +++ b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/ISettingV2AppService.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.SettingManagement; + +public interface ISettingV2AppService : IReadonlySettingV2AppService +{ + Task SetAsync(UpdateSettingsDto input); +} diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IUserSettingV2AppService.cs b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IUserSettingV2AppService.cs new file mode 100644 index 000000000..cef206c07 --- /dev/null +++ b/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/IUserSettingV2AppService.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.SettingManagement; + +public interface IUserSettingV2AppService : IApplicationService +{ + Task SetAsync(UpdateSettingsDto input); + + Task GetAsync(); +} diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/LINGYUN.Abp.Settings.csproj b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/LINGYUN.Abp.Settings.csproj index b1c22ea94..2a3e8f6a4 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/LINGYUN.Abp.Settings.csproj +++ b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/LINGYUN.Abp.Settings.csproj @@ -10,6 +10,7 @@ false false false + enable diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ISettingProviderExtensions.cs b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ISettingProviderExtensions.cs index f0b47e2b0..c77b28fd8 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ISettingProviderExtensions.cs +++ b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ISettingProviderExtensions.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.Settings; public static class ISettingProviderExtensions { - public static async Task GetOrDefaultAsync( + public static async Task GetOrDefaultAsync( [NotNull] this ISettingProvider settingProvider, [NotNull] string name, [NotNull] IServiceProvider serviceProvider) diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs new file mode 100644 index 000000000..e273ad654 --- /dev/null +++ b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Localization; + +namespace Volo.Abp.Settings; + +public static class SettingDefinitionExtensions +{ + private const string GroupKey = "Group"; + private const string ParentKey = "Parent"; + private const string OrderKey = "Order"; + private const string SlotKey = "Slot"; + private const string ValueTypeKey = "ValueType"; + private const string OptionNameKey = "OptionNames"; + private const string OptionValueKey = "OptionValues"; + private const string RequiredFeaturesKey = "RequiredFeatures"; + private const string RequiredPermissionsKey = "RequiredPermissions"; + + public static SettingDefinition RequiredFeatures( + this SettingDefinition definition, + IEnumerable requiredFeatures) + { + var existsRequiredFeatures = definition.GetRequiredFeatures(); + return definition + .WithProperty(RequiredFeaturesKey, existsRequiredFeatures.Union(requiredFeatures).JoinAsString(",")); + } + + public static SettingDefinition RequiredPermissions( + this SettingDefinition definition, + IEnumerable requiredPermissions) + { + var existsRequiredPermissions = definition.GetRequiredPermissions(); + return definition + .WithProperty(RequiredPermissionsKey, existsRequiredPermissions.Union(requiredPermissions).JoinAsString(",")); + } + + public static SettingDefinition WithSlot( + this SettingDefinition definition, + string slotName) + { + return definition + .WithProperty(SlotKey, slotName); + } + + public static SettingDefinition WithValueType( + this SettingDefinition definition, + ValueType valueType) + { + return definition + .WithProperty(ValueTypeKey, valueType.ToString()); + } + + public static SettingDefinition WithOrder( + this SettingDefinition definition, + int order) + { + return definition + .WithProperty(OrderKey, order.ToString()); + } + + public static SettingDefinition WithGroup( + this SettingDefinition definition, + string name, + string displayName, + int order = 0, + string[]? requiredFeatures = null, + string[]? requiredPermissions = null) + { + var groupDefinition = new SettingResourceDefinition( + name, + new FixedLocalizableString(displayName), + order, + requiredFeatures, + requiredPermissions); + + return definition + .WithProperty(GroupKey, groupDefinition.ToString()); + } + + public static SettingDefinition WithGroup( + this SettingDefinition definition, + string name, + LocalizableString displayName, + int order = 0, + string[]? requiredFeatures = null, + string[]? requiredPermissions = null) + { + var groupDefinition = new SettingResourceDefinition( + name, + displayName, + order, + requiredFeatures, + requiredPermissions); + + return definition + .WithProperty(GroupKey, groupDefinition.ToString()); + } + + public static SettingDefinition RequiredGroupFeatures( + this SettingDefinition definition, + string[] requiredFeatures) + { + var groupResource = definition.GetGroupOrNull(); + if (groupResource != null) + { + groupResource.RequiredFeatures = requiredFeatures + .Union(groupResource.RequiredFeatures ?? []) + .ToArray(); + + return definition + .WithProperty(GroupKey, groupResource.ToString()); + } + + return definition; + } + + public static SettingDefinition RequiredGroupPermissions( + this SettingDefinition definition, + string[] requiredPermissions) + { + var groupResource = definition.GetGroupOrNull(); + if (groupResource != null) + { + groupResource.RequiredPermissions = requiredPermissions + .Union(groupResource.RequiredPermissions ?? []) + .ToArray(); + + return definition + .WithProperty(GroupKey, groupResource.ToString()); + } + + return definition; + } + + public static SettingDefinition WithParent( + this SettingDefinition definition, + string name, + string displayName, + int order = 0, + string[]? requiredFeatures = null, + string[]? requiredPermissions = null) + { + var parentDefinition = new SettingResourceDefinition( + name, + new FixedLocalizableString(displayName), + order, + requiredFeatures, + requiredPermissions); + + return definition + .WithProperty(ParentKey, parentDefinition.ToString()); + } + + public static SettingDefinition WithParent( + this SettingDefinition definition, + string name, + LocalizableString displayName, + int order = 0, + string[]? requiredFeatures = null, + string[]? requiredPermissions = null) + { + var parentDefinition = new SettingResourceDefinition( + name, + displayName, + order, + requiredFeatures, + requiredPermissions); + + return definition + .WithProperty(ParentKey, parentDefinition.ToString()); + } + + public static SettingDefinition WithOptions( + this SettingDefinition definition, + IEnumerable> options) + { + var optionNames = options.Select(x => x.Name).JoinAsString(","); + var optionValues = options.Select(x => x.Value).JoinAsString(","); + + return definition + .WithValueType(ValueType.Option) + .WithProperty(OptionNameKey, optionNames) + .WithProperty(OptionValueKey, optionValues); + } + + public static SettingDefinition ReplaceProviders( + this SettingDefinition definition, + params string[] providers) + { + definition.Providers.Clear(); + + return definition.WithProviders(providers); + } + + public static string? GetSlotOrNull(this SettingDefinition definition) + { + if (definition.Properties.TryGetValue(SlotKey, out var slot) && slot != null) + { + return slot.ToString(); + } + + return null; + } + + public static ValueType GetValueTypeOrDefault(this SettingDefinition definition, ValueType defaultValueType = ValueType.String) + { + if (definition.Properties.TryGetValue(ValueTypeKey, out var valueTypeStr) && valueTypeStr != null && + Enum.TryParse(valueTypeStr.ToString(), out var valueType)) + { + return valueType; + } + + return defaultValueType; + } + + public static SettingResourceDefinition? GetGroupOrNull(this SettingDefinition definition) + { + return GetResourceOrNull(definition, GroupKey); + } + + public static SettingResourceDefinition? GetParentOrNull(this SettingDefinition definition) + { + return GetResourceOrNull(definition, ParentKey); + } + + public static IEnumerable> GetOptions(this SettingDefinition definition) + { + if (definition.TryGetArrayProperties(OptionNameKey, out var optionNames) && + definition.TryGetArrayProperties(OptionValueKey, out var optionValues)) + { + return optionNames.Select((name, index) => + { + return new NameValue(name, optionValues[index]); + }); + } + + return []; + } + + public static IEnumerable GetRequiredFeatures(this SettingDefinition definition) + { + definition.TryGetArrayProperties(RequiredFeaturesKey, out var requiredFeatures); + return requiredFeatures; + } + + public static IEnumerable GetRequiredPermissions(this SettingDefinition definition) + { + definition.TryGetArrayProperties(RequiredPermissionsKey, out var requiredPermissions); + return requiredPermissions; + } + + private static bool TryGetArrayProperties(this SettingDefinition definition, string propertyKey, out string[] enumerableProps) + { + if (definition.Properties.TryGetValue(propertyKey, out var propertyKeyValues) && propertyKeyValues != null) + { + enumerableProps = propertyKeyValues.ToString()!.Split(','); + return true; + } + enumerableProps = []; + return false; + } + + private static SettingResourceDefinition? GetResourceOrNull(SettingDefinition definition, string resourceKey) + { + if (definition.Properties.TryGetValue(resourceKey, out var resource) && resource != null) + { + var resourceDefineStr = resource.ToString(); + if (string.IsNullOrWhiteSpace(resourceDefineStr)) + { + return null; + } + var resourceDefineKeys = resourceDefineStr.Split(','); + if (resourceDefineKeys.Length < 6) + { + return null; + } + var name = resourceDefineKeys[0].Substring(2); + var displayName = resourceDefineKeys[1].Substring(2); + var resourceName = resourceDefineKeys[2]; + SettingResourceDefinition settingResource; + if (resourceName.Length > 2) + { + settingResource = new SettingResourceDefinition( + name, + new LocalizableString( + displayName, + resourceName.Substring(2))); + } + else + { + settingResource = new SettingResourceDefinition( + name, + new FixedLocalizableString(displayName)); + } + if (resourceDefineKeys[4].Length > 2) + { + settingResource.RequiredFeatures = resourceDefineKeys[4].Substring(2).Split(';'); + } + if (resourceDefineKeys[5].Length > 2) + { + settingResource.RequiredPermissions = resourceDefineKeys[5].Substring(2).Split(';'); + } + if (resourceDefineKeys[6].Length > 2 && int.TryParse(resourceDefineKeys[6].Substring(2), out var order)) + { + settingResource.Order = order; + } + + return settingResource; + } + + return null; + } +} diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingResourceDefinition.cs b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingResourceDefinition.cs new file mode 100644 index 000000000..e3285b588 --- /dev/null +++ b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingResourceDefinition.cs @@ -0,0 +1,119 @@ +using Microsoft.Extensions.Localization; +using System; +using System.Collections.Generic; +using System.Text; +using Volo.Abp.Localization; + +namespace Volo.Abp.Settings; + +public class SettingResourceDefinition +{ + public int Order { get; set; } + public string Name { get; set; } + public string? DisplayName { get; set; } + public string? ResourceName { get; set; } + public string? ResourceType { get; set; } + public string[]? RequiredFeatures { get; set; } + public string[]? RequiredPermissions { get; set; } + + public SettingResourceDefinition( + string name, + FixedLocalizableString displayName, + int order = 0, + string[]? requiredFeatures = null, + string[]? requiredPermissions = null) + { + Name = name; + Order = order; + DisplayName = displayName.Value; + RequiredFeatures = requiredFeatures; + RequiredPermissions = requiredPermissions; + } + + public SettingResourceDefinition( + string name, + LocalizableString displayName, + int order = 0, + string[]? requiredFeatures = null, + string[]? requiredPermissions = null) + { + Name = name; + Order = order; + ResourceName = displayName.ResourceName; + ResourceType = displayName.ResourceType?.FullName; + DisplayName = displayName.Name; + RequiredFeatures = requiredFeatures; + RequiredPermissions = requiredPermissions; + } + + public LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory) + { + if (!string.IsNullOrWhiteSpace(ResourceName) && + !string.IsNullOrWhiteSpace(DisplayName)) + { + if (!string.IsNullOrWhiteSpace(ResourceType)) + { + return new LocalizableString(DisplayName!, ResourceType).Localize(stringLocalizerFactory); + } + return new LocalizableString(DisplayName!, ResourceName).Localize(stringLocalizerFactory); + } + else if (!string.IsNullOrWhiteSpace(DisplayName)) + { + return new LocalizedString(Name!, DisplayName!); + } + return new LocalizedString(Name, Name); + } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.AppendFormat("N:{0}", Name); + sb.AppendFormat(",D:{0}", DisplayName ?? string.Empty); + sb.AppendFormat(",L:{0}", ResourceName ?? string.Empty); + sb.AppendFormat(",T:{0}", ResourceType ?? string.Empty); + sb.AppendFormat(",F:{0}", RequiredFeatures?.JoinAsString(";") ?? string.Empty); + sb.AppendFormat(",P:{0}", RequiredPermissions?.JoinAsString(";") ?? string.Empty); + sb.AppendFormat(",O:{0}", Order); + + return sb.ToString(); + } + + public override bool Equals(object? obj) + { + if (obj == null) + { + return false; + } + if (obj is SettingResourceDefinition other) + { + return string.Equals(Name, other.Name, StringComparison.CurrentCultureIgnoreCase); + } + + return false; + } + + public override int GetHashCode() + { + return StringComparer.CurrentCultureIgnoreCase.GetHashCode(Name); + } + + public static bool operator ==(SettingResourceDefinition? left, SettingResourceDefinition? right) + { + if (ReferenceEquals(left, right)) + { + return true; + } + + if (left is null || right is null) + { + return false; + } + + return left.Equals(right); + } + + public static bool operator !=(SettingResourceDefinition? left, SettingResourceDefinition? right) + { + return !(left == right); + } +} diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/ValueType.cs b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ValueType.cs similarity index 93% rename from aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/ValueType.cs rename to aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ValueType.cs index 000cc6c14..8288919a2 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.SettingManagement.Application.Contracts/LINGYUN/Abp/SettingManagement/Dto/ValueType.cs +++ b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/ValueType.cs @@ -1,4 +1,4 @@ -namespace LINGYUN.Abp.SettingManagement; +namespace Volo.Abp.Settings; public enum ValueType { diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/en.json index e7026f595..86c74c226 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/en.json @@ -24,6 +24,7 @@ "Features:WeChat.MiniProgram.SendLimit": "Send Limit", "Features:WeChat.MiniProgram.SendLimitDesc": "Limit wechat applet template message certain period", "Features:WeChat.MiniProgram.SendLimitInterval": "Send Duration", - "Features:WeChat.MiniProgram.SendLimitIntervalDesc": "Limit template message can be invoked, unit is Month" + "Features:WeChat.MiniProgram.SendLimitIntervalDesc": "Limit template message can be invoked, unit is Month", + "Settings:WeChat.MiniProgram": "WeChat Mini Program" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/zh-Hans.json index e09f24529..1abfaf7ba 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Localization/Resources/zh-Hans.json @@ -24,6 +24,7 @@ "Features:WeChat.MiniProgram.SendLimit": "发送消息限制", "Features:WeChat.MiniProgram.SendLimitDesc": "在一定周期内限制微信小程序模板消息调用上限", "Features:WeChat.MiniProgram.SendLimitInterval": "发送消息限制时长", - "Features:WeChat.MiniProgram.SendLimitIntervalDesc": "限制模板消息调用上限的时长,周期为月" + "Features:WeChat.MiniProgram.SendLimitIntervalDesc": "限制模板消息调用上限的时长,周期为月", + "Settings:WeChat.MiniProgram": "微信小程序" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Settings/WeChatMiniProgramSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Settings/WeChatMiniProgramSettingDefinitionProvider.cs index f01767e8f..1e838849d 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Settings/WeChatMiniProgramSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.MiniProgram/LINGYUN/Abp/WeChat/MiniProgram/Settings/WeChatMiniProgramSettingDefinitionProvider.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.WeChat.Localization; +using LINGYUN.Abp.WeChat.MiniProgram.Features; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,7 @@ namespace LINGYUN.Abp.WeChat.MiniProgram.Settings; public class WeChatMiniProgramSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "WeChat"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -19,7 +21,13 @@ public class WeChatMiniProgramSettingDefinitionProvider : SettingDefinitionProvi DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChat"), + requiredFeatures: [WeChatMiniProgramFeatures.Enable]) + .WithParent("MiniProgram", L("Settings:WeChat.MiniProgram"), order: 1) + .WithOrder(0), new SettingDefinition( WeChatMiniProgramSettingNames.AppSecret, "", L("DisplayName:WeChat.MiniProgram.AppSecret"), @@ -30,7 +38,13 @@ public class WeChatMiniProgramSettingDefinitionProvider : SettingDefinitionProvi DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChat"), + requiredFeatures: [WeChatMiniProgramFeatures.Enable]) + .WithParent("MiniProgram", L("Settings:WeChat.MiniProgram"), order: 1) + .WithOrder(1), new SettingDefinition( WeChatMiniProgramSettingNames.Token, "", L("DisplayName:WeChat.MiniProgram.Token"), @@ -41,7 +55,13 @@ public class WeChatMiniProgramSettingDefinitionProvider : SettingDefinitionProvi DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChat"), + requiredFeatures: [WeChatMiniProgramFeatures.Enable]) + .WithParent("MiniProgram", L("Settings:WeChat.MiniProgram"), order: 1) + .WithOrder(2), new SettingDefinition( WeChatMiniProgramSettingNames.EncodingAESKey, "", L("DisplayName:WeChat.MiniProgram.EncodingAESKey"), @@ -53,10 +73,16 @@ public class WeChatMiniProgramSettingDefinitionProvider : SettingDefinitionProvi ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChat"), + requiredFeatures: [WeChatMiniProgramFeatures.Enable]) + .WithParent("MiniProgram", L("Settings:WeChat.MiniProgram"), order: 1) + .WithOrder(3) ); } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/en.json index 125dcd1e1..0d26cfa08 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/en.json @@ -14,6 +14,7 @@ "DisplayName:WeChat.Official.Token": "Token", "Description:WeChat.Official.Token": "Token,See:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html", "DisplayName:WeChat.Official.EncodingAESKey": "Encoding AES Key", - "Description:WeChat.Official.EncodingAESKey": "Encoding AES Key,See:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html" + "Description:WeChat.Official.EncodingAESKey": "Encoding AES Key,See:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html", + "Settings:WeChat.Official": "WeChat Official" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json index 9f0f4124d..4d9f268cd 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json @@ -16,6 +16,7 @@ "DisplayName:WeChat.Official.Token": "公众号Token", "Description:WeChat.Official.Token": "微信公众号Token,详情见:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html", "DisplayName:WeChat.Official.EncodingAESKey": "公众号EncodingAESKey", - "Description:WeChat.Official.EncodingAESKey": "微信公众号EncodingAESKey,详情见:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html" + "Description:WeChat.Official.EncodingAESKey": "微信公众号EncodingAESKey,详情见:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html", + "Settings:WeChat.Official": "微信公众号" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs index 22144d7ab..7a46dd3be 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.WeChat.Localization; +using LINGYUN.Abp.WeChat.Official.Features; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,7 @@ namespace LINGYUN.Abp.WeChat.Official.Settings; public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "WeChat"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -20,7 +22,14 @@ public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent( + "Official", + L("Settings:WeChat.Official"), + requiredFeatures: [WeChatOfficialFeatures.Enable], order: 2) + .WithOrder(0) + .WithValueType(ValueType.Boolean), new SettingDefinition( WeChatOfficialSettingNames.AppId, "", L("DisplayName:WeChat.Official.AppId"), @@ -31,7 +40,13 @@ public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent( + "Official", + L("Settings:WeChat.Official"), + requiredFeatures: [WeChatOfficialFeatures.Enable], order: 2) + .WithOrder(1), new SettingDefinition( WeChatOfficialSettingNames.AppSecret, "", L("DisplayName:WeChat.Official.AppSecret"), @@ -42,7 +57,13 @@ public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent( + "Official", + L("Settings:WeChat.Official"), + requiredFeatures: [WeChatOfficialFeatures.Enable], order: 2) + .WithOrder(2), new SettingDefinition( WeChatOfficialSettingNames.Url, "", L("DisplayName:WeChat.Official.Url"), @@ -53,7 +74,13 @@ public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent( + "Official", + L("Settings:WeChat.Official"), + requiredFeatures: [WeChatOfficialFeatures.Enable], order: 2) + .WithOrder(3), new SettingDefinition( WeChatOfficialSettingNames.Token, "", L("DisplayName:WeChat.Official.Token"), @@ -64,7 +91,13 @@ public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent( + "Official", + L("Settings:WeChat.Official"), + requiredFeatures: [WeChatOfficialFeatures.Enable], order: 2) + .WithOrder(4), new SettingDefinition( WeChatOfficialSettingNames.EncodingAESKey, "", L("DisplayName:WeChat.Official.EncodingAESKey"), @@ -76,10 +109,16 @@ public class WeChatOfficialSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent( + "Official", + L("Settings:WeChat.Official"), + requiredFeatures: [WeChatOfficialFeatures.Enable], order: 2) + .WithOrder(5) ); } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/en.json index 220b6cda1..228af7edc 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/en.json @@ -6,6 +6,7 @@ "Features:ContactsEnable": "Enable Contacts", "Features:ContactsEnableDesc": "Enable the ability to provide the application with an Enterprise wechat contacts interface.", "DisplayName:WeChatWorkContact.Secret": "Contact Secret", - "Description:WeChatWorkContact.Secret": "Secretfor the address contact application. Some contact interfaces require a contact synchronization secret." + "Description:WeChatWorkContact.Secret": "Secretfor the address contact application. Some contact interfaces require a contact synchronization secret.", + "Settings:WeChatWork.WeChatWorkContact": "Contacts" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/zh-Hans.json index acfe3b0a1..0bccc98a9 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Localization/Resources/zh-Hans.json @@ -6,6 +6,7 @@ "Features:ContactsEnable": "启用通讯录", "Features:ContactsEnableDesc": "启用以使应用拥有企业微信通讯录接口的能力.", "DisplayName:WeChatWorkContact.Secret": "通讯录访问密钥", - "Description:WeChatWorkContact.Secret": "通讯录应用访问密钥,部分通讯录接口需要通讯录同步secret." + "Description:WeChatWorkContact.Secret": "通讯录应用访问密钥,部分通讯录接口需要通讯录同步secret.", + "Settings:WeChatWork.WeChatWorkContact": "通讯录" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Settings/WeChatWorkContactSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Settings/WeChatWorkContactSettingDefinitionProvider.cs index dc6234c7b..9f4e0d1d9 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Settings/WeChatWorkContactSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Contacts/LINGYUN/Abp/WeChat/Work/Contacts/Settings/WeChatWorkContactSettingDefinitionProvider.cs @@ -1,4 +1,6 @@ -using LINGYUN.Abp.WeChat.Work.Localization; +using LINGYUN.Abp.WeChat.Work.Contacts.Features; +using LINGYUN.Abp.WeChat.Work.Features; +using LINGYUN.Abp.WeChat.Work.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +8,7 @@ namespace LINGYUN.Abp.WeChat.Work.Contacts.Settings; public class WeChatWorkContactSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "WeChatWork"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -20,10 +23,19 @@ public class WeChatWorkContactSettingDefinitionProvider : SettingDefinitionProvi ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent( + "WeChatWorkContact", + L("Settings:WeChatWork.WeChatWorkContact"), + requiredFeatures: [WeChatWorkContactsFeatureNames.Enable], order: 3) + .WithOrder(0) ); } - private static ILocalizableString L(string name) + private static LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/en.json index c5771d568..5ae43058d 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/en.json @@ -6,6 +6,7 @@ "Features:ExternalContactEnable": "Enable External Contact", "Features:ExternalContactEnableDesc": "Enable the ability to provide the application with an Enterprise wechat customer contact interface.", "DisplayName:WeChatWorkExternalContact.Secret": "External Contact Secret", - "Description:WeChatWorkExternalContact.Secret": "Customer contact application access key, some customer contact interfaces require customer contact application secret." + "Description:WeChatWorkExternalContact.Secret": "Customer contact application access key, some customer contact interfaces require customer contact application secret.", + "Settings:WeChatWork.WeChatWorkExternalContact": "External Contact" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/zh-Hans.json index 89b15b6ba..f1dfdf81c 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Localization/Resources/zh-Hans.json @@ -6,6 +6,7 @@ "Features:ExternalContactEnable": "启用客户联系", "Features:ExternalContactEnableDesc": "启用以使应用拥有企业微信客户联系接口的能力.", "DisplayName:WeChatWorkExternalContact.Secret": "客户联系访问密钥", - "Description:WeChatWorkExternalContact.Secret": "客户联系应用访问密钥,部分客户联系接口需要客户联系应用secret." + "Description:WeChatWorkExternalContact.Secret": "客户联系应用访问密钥,部分客户联系接口需要客户联系应用secret.", + "Settings:WeChatWork.WeChatWorkExternalContact": "客户联系" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Settings/WeChatWorkExternalContactSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Settings/WeChatWorkExternalContactSettingDefinitionProvider.cs index 14743d89d..67de39da4 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Settings/WeChatWorkExternalContactSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.ExternalContact/LINGYUN/Abp/WeChat/Work/ExternalContact/Settings/WeChatWorkExternalContactSettingDefinitionProvider.cs @@ -1,4 +1,6 @@ -using LINGYUN.Abp.WeChat.Work.Localization; +using LINGYUN.Abp.WeChat.Work.ExternalContact.Features; +using LINGYUN.Abp.WeChat.Work.Features; +using LINGYUN.Abp.WeChat.Work.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +8,7 @@ namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Settings; public class WeChatWorkExternalContactSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "WeChatWork"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -20,10 +23,19 @@ public class WeChatWorkExternalContactSettingDefinitionProvider : SettingDefinit ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent( + "WeChatWorkExternalContact", + L("Settings:WeChatWork.WeChatWorkExternalContact"), + requiredFeatures: [WeChatWorkExternalContactFeatureNames.Enable], order: 4) + .WithOrder(0) ); } - private static ILocalizableString L(string name) + private static LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj index dc4b33b04..be0c19238 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj @@ -29,6 +29,7 @@ + diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json index 1b59d4f25..517659308 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/en.json @@ -76,6 +76,9 @@ "WeChatWork:40009": "上传图片大小不是有效值,参考:https://developer.work.weixin.qq.com/document/path/90313#10112/%E4%B8%8A%E4%BC%A0%E7%9A%84%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6%E9%99%90%E5%88%B6", "WeChatWork:40011": "上传视频大小不是有效值,参考:https://developer.work.weixin.qq.com/document/path/90313#10112/%E4%B8%8A%E4%BC%A0%E7%9A%84%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6%E9%99%90%E5%88%B6", "WeChatWork:40013": "不合法的CorpID", - "WeChatWork:40014": "不合法的access_token,参考:https://developer.work.weixin.qq.com/document/path/90313#10649/%E9%94%99%E8%AF%AF%E7%A0%81%EF%BC%9A40014" + "WeChatWork:40014": "不合法的access_token,参考:https://developer.work.weixin.qq.com/document/path/90313#10649/%E9%94%99%E8%AF%AF%E7%A0%81%EF%BC%9A40014", + "Settings:WeChatWork": "WeChat Work", + "Settings:WeChatWork.UserLogin": "User Login", + "Settings:WeChatWork.Connection": "Connection" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json index dc1138b07..20c182d85 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Localization/Resources/zh-Hans.json @@ -76,6 +76,9 @@ "WeChatWork:40009": "上传图片大小不是有效值,参考:https://developer.work.weixin.qq.com/document/path/90313#10112/%E4%B8%8A%E4%BC%A0%E7%9A%84%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6%E9%99%90%E5%88%B6", "WeChatWork:40011": "上传视频大小不是有效值,参考:https://developer.work.weixin.qq.com/document/path/90313#10112/%E4%B8%8A%E4%BC%A0%E7%9A%84%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6%E9%99%90%E5%88%B6", "WeChatWork:40013": "不合法的CorpID", - "WeChatWork:40014": "不合法的access_token,参考:https://developer.work.weixin.qq.com/document/path/90313#10649/%E9%94%99%E8%AF%AF%E7%A0%81%EF%BC%9A40014" + "WeChatWork:40014": "不合法的access_token,参考:https://developer.work.weixin.qq.com/document/path/90313#10649/%E9%94%99%E8%AF%AF%E7%A0%81%EF%BC%9A40014", + "Settings:WeChatWork": "企业微信", + "Settings:WeChatWork.UserLogin": "用户登录", + "Settings:WeChatWork.Connection": "连接配置" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs index 33181b4e6..eb8d8aa0a 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Settings/WeChatWorkSettingDefinitionProvider.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.WeChat.Work.Localization; +using LINGYUN.Abp.WeChat.Work.Features; +using LINGYUN.Abp.WeChat.Work.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,7 @@ namespace LINGYUN.Abp.WeChat.Work.Settings; public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "WeChatWork"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -22,6 +24,13 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent("UserLogin", L("Settings:WeChatWork.UserLogin"), order: 1) + .WithOrder(0) + .WithValueType(ValueType.Boolean) ); context.Add(GetConnectionSettings()); } @@ -39,7 +48,13 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent("Connection", L("Settings:WeChatWork.Connection"), order: 2) + .WithOrder(0), new SettingDefinition( WeChatWorkSettingNames.Connection.AgentId, @@ -50,7 +65,13 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent("Connection", L("Settings:WeChatWork.Connection"), order: 2) + .WithOrder(1), new SettingDefinition( WeChatWorkSettingNames.Connection.Secret, displayName: L("DisplayName:WeChatWork.Connection.Secret"), @@ -60,7 +81,13 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent("Connection", L("Settings:WeChatWork.Connection"), order: 2) + .WithOrder(2), new SettingDefinition( WeChatWorkSettingNames.Connection.Token, displayName: L("DisplayName:WeChatWork.Connection.Token"), @@ -70,7 +97,13 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent("Connection", L("Settings:WeChatWork.Connection"), order: 2) + .WithOrder(3), new SettingDefinition( WeChatWorkSettingNames.Connection.EncodingAESKey, displayName: L("DisplayName:WeChatWork.Connection.EncodingAESKey"), @@ -80,11 +113,17 @@ public class WeChatWorkSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:WeChatWork"), + requiredFeatures: [WeChatWorkFeatureNames.Enable]) + .WithParent("Connection", L("Settings:WeChatWork.Connection"), order: 2) + .WithOrder(4), }; } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj index 830a2dd39..3f51d3464 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj @@ -29,6 +29,7 @@ + diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/en.json index 08d22a9e3..8fac2480d 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/en.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/en.json @@ -7,6 +7,8 @@ "Description:WeChat": "WeChat", "UserLogin": "User Login", "DisplayName:WeChat.EnabledQuickLogin": "Enabled Quick Login", - "Description:WeChat.EnabledQuickLogin": "Users can login directly with the code given by wx.login when they are not registered" + "Description:WeChat.EnabledQuickLogin": "Users can login directly with the code given by wx.login when they are not registered", + "Settings:WeChat": "WeChat", + "Settings:WeChat.UserLogin": "User Login" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/zh-Hans.json index 81c06a287..eab66bc98 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/zh-Hans.json +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Localization/Resources/zh-Hans.json @@ -7,6 +7,8 @@ "Description:WeChat": "微信开发平台", "UserLogin": "用户登录", "DisplayName:WeChat.EnabledQuickLogin": "启用快捷登录", - "Description:WeChat.EnabledQuickLogin": "用户可在未注册时通过 wx.login 得到的code直接登录" + "Description:WeChat.EnabledQuickLogin": "用户可在未注册时通过 wx.login 得到的code直接登录", + "Settings:WeChat": "微信开发", + "Settings:WeChat.UserLogin": "用户登录" } } \ No newline at end of file diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingDefinitionProvider.cs index feb0844b3..0a093772d 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Settings/WeChatSettingDefinitionProvider.cs @@ -6,6 +6,8 @@ namespace LINGYUN.Abp.WeChat.Settings; public class WeChatSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "WeChat"; + public override void Define(ISettingDefinitionContext context) { context.Add( @@ -22,10 +24,14 @@ public class WeChatSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:WeChat")) + .WithParent("UserLogin", L("Settings:WeChat.UserLogin"), order: 0) + .WithOrder(0) + .WithValueType(ValueType.Boolean) ); } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountGroupSettingDefinitionProvider.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountGroupSettingDefinitionProvider.cs new file mode 100644 index 000000000..7244255cf --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountGroupSettingDefinitionProvider.cs @@ -0,0 +1,31 @@ +using Volo.Abp.Account.Localization; +using Volo.Abp.Account.Settings; +using Volo.Abp.Localization; +using Volo.Abp.Settings; +using ValueType = Volo.Abp.Settings.ValueType; + +namespace LINGYUN.Abp.Account; + +public class AccountGroupSettingDefinitionProvider : SettingDefinitionProvider +{ + private const string GroupName = "Identity"; + private const int GroupOrder = 10; + public override void Define(ISettingDefinitionContext context) + { + context.GetOrNull(AccountSettingNames.EnableLocalLogin) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Account", L("Settings:Identity.Account"), order: 0) + ?.WithOrder(0) + ?.WithValueType(ValueType.Boolean); + context.GetOrNull(AccountSettingNames.IsSelfRegistrationEnabled) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Account", L("Settings:Identity.Account"), order: 0) + ?.WithOrder(1) + ?.WithValueType(ValueType.Boolean); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN.Abp.Account.OAuth.csproj b/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN.Abp.Account.OAuth.csproj index d097d8b31..30eaf6d9b 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN.Abp.Account.OAuth.csproj +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN.Abp.Account.OAuth.csproj @@ -23,4 +23,8 @@ + + + +
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN/Abp/Account/OAuth/Settings/AccountOAuthSettingDefinitionProvider.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN/Abp/Account/OAuth/Settings/AccountOAuthSettingDefinitionProvider.cs index dba71ecbf..d8d1da0b2 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN/Abp/Account/OAuth/Settings/AccountOAuthSettingDefinitionProvider.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.OAuth/LINGYUN/Abp/Account/OAuth/Settings/AccountOAuthSettingDefinitionProvider.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.Account.OAuth.Localization; +using LINGYUN.Abp.Account.OAuth.Features; +using LINGYUN.Abp.Account.OAuth.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,8 @@ namespace LINGYUN.Abp.Account.OAuth.Settings; public class AccountOAuthSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "ExternalOAuthLogin"; + public override void Define(ISettingDefinitionContext context) { context.Add(GetGitHubSettings()); @@ -26,7 +29,10 @@ public class AccountOAuthSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:ExternalOAuthLogin")) + .WithParent("GitHubAuth", L("Settings:GitHubAuth")) + .RequiredFeatures([AccountOAuthFeatureNames.GitHub.Enable]), new SettingDefinition( AccountOAuthSettingNames.GitHub.ClientSecret, displayName: L("Settings:GitHubClientSecret"), @@ -37,7 +43,10 @@ public class AccountOAuthSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:ExternalOAuthLogin")) + .WithParent("GitHubAuth", L("Settings:GitHubAuth")) + .RequiredFeatures([AccountOAuthFeatureNames.GitHub.Enable]), }; } @@ -55,7 +64,10 @@ public class AccountOAuthSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:ExternalOAuthLogin")) + .WithParent("Bilibili", L("Settings:BilibiliAuth")) + .RequiredFeatures([AccountOAuthFeatureNames.Bilibili.Enable]), new SettingDefinition( AccountOAuthSettingNames.Bilibili.ClientSecret, displayName: L("Settings:BilibiliClientSecret"), @@ -66,11 +78,14 @@ public class AccountOAuthSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:ExternalOAuthLogin")) + .WithParent("Bilibili", L("Settings:BilibiliAuth")) + .RequiredFeatures([AccountOAuthFeatureNames.Bilibili.Enable]), }; } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json index df80fdea6..5eb375163 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/en.json @@ -60,6 +60,8 @@ "Propertites": "Propertites", "Tools:New": "New Tool", "Tools:Edit": "Edit Tool", - "DesignConversationNamePrompt": "Based on the user's question, generate a concise and descriptive conversation title, with the length limited to {0} characters or less." + "DesignConversationNamePrompt": "Based on the user's question, generate a concise and descriptive conversation title, with the length limited to {0} characters or less.", + "Settings:AIManagement": "Artificia Intelligence", + "Settings:AIManagement.ChatMessage": "Chats" } } \ No newline at end of file diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json index 9004b5a3b..5c97079d8 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Localization/Resources/zh-Hans.json @@ -60,6 +60,8 @@ "Propertites": "属性", "Tools:New": "新工具", "Tools:Edit": "编辑工具", - "DesignConversationNamePrompt": "根据用户的提问, 生成一个简短且具有描述性的对话名称, 长度必须控制在 {0} 个字符以内." + "DesignConversationNamePrompt": "根据用户的提问, 生成一个简短且具有描述性的对话名称, 长度必须控制在 {0} 个字符以内.", + "Settings:AIManagement": "人工智能", + "Settings:AIManagement.ChatMessage": "对话管理" } } \ No newline at end of file diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN.Abp.AIManagement.Domain.csproj b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN.Abp.AIManagement.Domain.csproj index 390c80eb8..43b66c12b 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN.Abp.AIManagement.Domain.csproj +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN.Abp.AIManagement.Domain.csproj @@ -23,6 +23,7 @@ + diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingDefinitionProvider.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingDefinitionProvider.cs index e36886420..0ab341956 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingDefinitionProvider.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingDefinitionProvider.cs @@ -5,6 +5,7 @@ using Volo.Abp.Settings; namespace LINGYUN.Abp.AIManagement.Settings; public class AIManagementSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "AIManagement"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -12,10 +13,19 @@ public class AIManagementSettingDefinitionProvider : SettingDefinitionProvider AIManagementSettingNames.ChatMessage.MaxLatestHistoryMessagesToKeep, defaultValue: "5", displayName: L("DisplayName:MaxLatestHistoryMessagesToKeep"), - description: L("Description:MaxLatestHistoryMessagesToKeep"))); + description: L("Description:MaxLatestHistoryMessagesToKeep")) + .WithProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:AIManagement")) + .WithParent("ChatMessage", L("Settings:AIManagement.ChatMessage")) + .WithValueType(ValueType.Number) + ); } - private static ILocalizableString L(string name) + private static LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobManagementPermissionSettingDefinitionProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobManagementPermissionSettingDefinitionProvider.cs new file mode 100644 index 000000000..c790d8aee --- /dev/null +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Application/LINGYUN/Abp/BlobManagement/BlobManagementPermissionSettingDefinitionProvider.cs @@ -0,0 +1,18 @@ +using LINGYUN.Abp.BlobManagement.Permissions; +using LINGYUN.Abp.BlobManagement.Settings; +using Volo.Abp.Settings; + +namespace LINGYUN.Abp.BlobManagement; + +public class BlobManagementPermissionSettingDefinitionProvider : SettingDefinitionProvider +{ + public override void Define(ISettingDefinitionContext context) + { + context.GetOrNull(BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds) + ?.RequiredGroupPermissions([BlobManagementPermissionNames.Blob.Default]); + context.GetOrNull(BlobManagementSettingNames.FileLimitLength) + ?.RequiredGroupPermissions([BlobManagementPermissionNames.Blob.Default]); + context.GetOrNull(BlobManagementSettingNames.AllowFileExtensions) + ?.RequiredGroupPermissions([BlobManagementPermissionNames.Blob.Default]); + } +} diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN.Abp.BlobManagement.Domain.Shared.csproj b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN.Abp.BlobManagement.Domain.Shared.csproj index f42e52994..9b17ae78b 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN.Abp.BlobManagement.Domain.Shared.csproj +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN.Abp.BlobManagement.Domain.Shared.csproj @@ -24,4 +24,8 @@ + + + +
diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json index 7babc31ef..9fe94e364 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/en.json @@ -75,6 +75,8 @@ "UploadStatus:Error": "Error", "UploadStatus:Pause": "Pause", "BlobWellDownloadMessage": "The file download is about to start.", - "BlobCanNotPreviewMessage": "This file does not support previewing. Please download it and view it!" + "BlobCanNotPreviewMessage": "This file does not support previewing. Please download it and view it!", + "Settings:BlobManagement": "Blob Management", + "Settings:BlobManagement.Blobs": "Blobs" } } \ No newline at end of file diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json index 59f356251..35a8c044f 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Localization/Resources/zh-Hans.json @@ -75,6 +75,8 @@ "UploadStatus:Error": "错误", "UploadStatus:Pause": "暂停", "BlobWellDownloadMessage": "即将开始下载文件.", - "BlobCanNotPreviewMessage": "此文件不支持预览,请下载后查看!" + "BlobCanNotPreviewMessage": "此文件不支持预览,请下载后查看!", + "Settings:BlobManagement": "对象存储", + "Settings:BlobManagement.Blobs": "存储管理" } } \ No newline at end of file diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs index e8d1f886f..85fadd703 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.Domain.Shared/LINGYUN/Abp/BlobManagement/Settings/BlobManagementSettingDefinitionProvider.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.BlobManagement.Localization; +using LINGYUN.Abp.BlobManagement.Features; +using LINGYUN.Abp.BlobManagement.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,6 +7,7 @@ namespace LINGYUN.Abp.BlobManagement.Settings; public class BlobManagementSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "BlobManagement"; public override void Define(ISettingDefinitionContext context) { context.Add(CreateBlobFileSettings()); @@ -25,7 +27,13 @@ public class BlobManagementSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:BlobManagement"), + requiredFeatures: [BlobManagementFeatureNames.Blob.Enable]) + .WithParent("Blobs", L("Settings:BlobManagement.Blobs")) + .WithValueType(ValueType.Number), new SettingDefinition( name: BlobManagementSettingNames.AllowFileExtensions, defaultValue: BlobManagementSettingNames.DefaultAllowFileExtensions, @@ -36,18 +44,29 @@ public class BlobManagementSettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:BlobManagement"), + requiredFeatures: [BlobManagementFeatureNames.Blob.Enable]) + .WithParent("Blobs", L("Settings:BlobManagement.Blobs")), new SettingDefinition( name: BlobManagementSettingNames.GenerateDownloadUrlExpirySeconds, defaultValue: BlobManagementSettingNames.DefaultGenerateDownloadUrlExpirySeconds.ToString(), displayName: L("DisplayName:GenerateDownloadUrlExpirySeconds"), description: L("Description:GenerateDownloadUrlExpirySeconds"), - isVisibleToClients: true) + isVisibleToClients: false) .WithProviders( DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup( + GroupName, + L("Settings:BlobManagement"), + requiredFeatures: [BlobManagementFeatureNames.Blob.Enable]) + .WithParent("Blobs", L("Settings:BlobManagement.Blobs")) + .WithValueType(ValueType.Number), }; } diff --git a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs index 1a6cfa5e1..bf3fb06bc 100644 --- a/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs +++ b/aspnet-core/modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN/Abp/BlobManagement/SettingManagement/BlobManagementSettingAppService.cs @@ -9,7 +9,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.MultiTenancy; using Volo.Abp.SettingManagement; using Volo.Abp.Settings; -using ValueType = LINGYUN.Abp.SettingManagement.ValueType; +using ValueType = Volo.Abp.Settings.ValueType; namespace LINGYUN.Abp.BlobManagement.SettingManagement; diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN.Abp.Identity.Domain.Shared.csproj b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN.Abp.Identity.Domain.Shared.csproj index 14dc78e74..8aea49bef 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN.Abp.Identity.Domain.Shared.csproj +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN.Abp.Identity.Domain.Shared.csproj @@ -27,4 +27,8 @@ + + + +
diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json index 80d38aba9..1059016d6 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json @@ -116,6 +116,14 @@ "CurrentSession": "Current Session", "RevokeSession": "Revoke Session", "SessionWillBeRevokedMessage": "The selected session will be revoked, which will invalidate the user's login!", - "SuccessfullyRevoked": "Successful session revoked" + "SuccessfullyRevoked": "Successful session revoked", + "Settings:Identity": "Identity", + "Settings:Identity.User": "User", + "Settings:Identity.Lockout": "Lockout", + "Settings:Identity.SignIn": "SignIn", + "Settings:Identity.Password": "Password", + "Settings:Identity.OrganizationUnit": "OrganizationUnit", + "Settings:Identity.Session": "Session", + "Settings:Identity.Link": "Link" } } \ No newline at end of file diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json index 2dfb6959b..1d4b0dacd 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json @@ -116,6 +116,14 @@ "CurrentSession": "当前会话", "RevokeSession": "撤销会话", "SessionWillBeRevokedMessage": "选择的会话将被撤销,此操作使目标登录失效!", - "SuccessfullyRevoked": "撤销会话成功" + "SuccessfullyRevoked": "撤销会话成功", + "Settings:Identity": "身份认证", + "Settings:Identity.User": "用户配置", + "Settings:Identity.Lockout": "用户锁定", + "Settings:Identity.SignIn": "用户登录", + "Settings:Identity.Password": "密码配置", + "Settings:Identity.OrganizationUnit": "组织机构", + "Settings:Identity.Session": "会话配置", + "Settings:Identity.Link": "链接" } } \ No newline at end of file diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs index 3c764fd5d..5deb67d9e 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Settings/IdentitySettingDefinitionProvider.cs @@ -1,4 +1,6 @@ -using Volo.Abp.Identity.Localization; +using Microsoft.Extensions.Localization; +using Volo.Abp; +using Volo.Abp.Identity.Localization; using Volo.Abp.Localization; using Volo.Abp.Settings; @@ -6,8 +8,20 @@ namespace LINGYUN.Abp.Identity.Settings; public class IdentitySettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "Identity"; + private const int GroupOrder = 10; + + protected IStringLocalizerFactory StringLocalizerFactory { get; } + + public IdentitySettingDefinitionProvider(IStringLocalizerFactory stringLocalizerFactory) + { + StringLocalizerFactory = stringLocalizerFactory; + } + public override void Define(ISettingDefinitionContext context) { + var stringLocalizer = StringLocalizerFactory.Create(); + context.Add( new SettingDefinition( name: IdentitySettingNames.User.SmsNewUserRegister, @@ -19,7 +33,11 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("User", L("Settings:Identity.User"), order: 1) + .WithOrder(0) + .WithValueType(ValueType.String), new SettingDefinition( name: IdentitySettingNames.User.SmsUserSignin, defaultValue: "", @@ -30,7 +48,11 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("User", L("Settings:Identity.User"), order: 1) + .WithOrder(1) + .WithValueType(ValueType.String), new SettingDefinition( name: IdentitySettingNames.User.SmsResetPassword, defaultValue: "", @@ -41,7 +63,11 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("User", L("Settings:Identity.User"), order: 1) + .WithOrder(2) + .WithValueType(ValueType.String), new SettingDefinition( name: IdentitySettingNames.User.SmsPhoneNumberConfirmed, defaultValue: "", @@ -52,7 +78,11 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("User", L("Settings:Identity.User"), order: 1) + .WithOrder(3) + .WithValueType(ValueType.String), new SettingDefinition( name: IdentitySettingNames.User.SmsRepetInterval, defaultValue: "5", @@ -63,7 +93,11 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("User", L("Settings:Identity.User"), order: 1) + .WithOrder(4) + .WithValueType(ValueType.Number), new SettingDefinition( name: IdentitySettingNames.Session.ConcurrentLoginStrategy, defaultValue: ConcurrentLoginStrategy.None.ToString(), @@ -74,7 +108,16 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("Session", L("Settings:Identity.Session"), order: 5) + .WithOrder(0) + .WithOptions([ + new NameValue(stringLocalizer["ConcurrentLoginStrategy:None"].Value, ConcurrentLoginStrategy.None.ToString()), + new NameValue(stringLocalizer["ConcurrentLoginStrategy:LogoutFromSameTypeDevicesLimit"].Value, ConcurrentLoginStrategy.LogoutFromSameTypeDevicesLimit.ToString()), + new NameValue(stringLocalizer["ConcurrentLoginStrategy:LogoutFromSameTypeDevices"].Value, ConcurrentLoginStrategy.LogoutFromSameTypeDevices.ToString()), + new NameValue(stringLocalizer["ConcurrentLoginStrategy:LogoutFromAllDevices"].Value, ConcurrentLoginStrategy.LogoutFromAllDevices.ToString()), + ]), new SettingDefinition( name: IdentitySettingNames.Session.LogoutFromSameTypeDevicesLimit, defaultValue: "1", @@ -85,7 +128,11 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider DefaultValueSettingValueProvider.ProviderName, ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName), + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("Session", L("Settings:Identity.Session"), order: 5) + .WithOrder(1) + .WithValueType(ValueType.Number), new SettingDefinition( name: IdentitySettingNames.Link.UserLoginUri, @@ -98,6 +145,10 @@ public class IdentitySettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("Link", L("Settings:Identity.Link"), order: 7) + .WithOrder(0) + .WithValueType(ValueType.String) ); } diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN.Abp.Identity.Domain.csproj b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN.Abp.Identity.Domain.csproj index d420b343d..cc7a232d5 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN.Abp.Identity.Domain.csproj +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN.Abp.Identity.Domain.csproj @@ -18,6 +18,7 @@ + diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityGroupSettingDefinitionProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityGroupSettingDefinitionProvider.cs new file mode 100644 index 000000000..cc1cbd211 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IdentityGroupSettingDefinitionProvider.cs @@ -0,0 +1,247 @@ +using Volo.Abp.Identity.Localization; +using Volo.Abp.Identity.Settings; +using Volo.Abp.Localization; +using Volo.Abp.Settings; +using ValueType = Volo.Abp.Settings.ValueType; + +namespace LINGYUN.Abp.Identity; + +public class IdentityGroupSettingDefinitionProvider : SettingDefinitionProvider +{ + private const string GroupName = "Identity"; + private const int GroupOrder = 10; + + public override void Define(ISettingDefinitionContext context) + { + SetLockoutSettingGroup(context); + SetUserSettingGroup(context); + SetSignInSettingGroup(context); + SetPasswordSettingGroup(context); + SetOrganizationUnitSettingGroup(context); + } + + private static void SetLockoutSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(IdentitySettingNames.Lockout.AllowedForNewUsers) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Lockout", L("Settings:Identity.Lockout"), order: 3) + ?.WithOrder(0) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Lockout.LockoutDuration) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Lockout", L("Settings:Identity.Lockout"), order: 3) + ?.WithOrder(1) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Lockout.MaxFailedAccessAttempts) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Lockout", L("Settings:Identity.Lockout"), order: 3) + ?.WithOrder(2) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + + private static void SetUserSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(IdentitySettingNames.User.IsEmailUpdateEnabled) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("User", L("Settings:Identity.User"), order: 1) + ?.WithOrder(0) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.User.IsUserNameUpdateEnabled) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("User", L("Settings:Identity.User"), order: 1) + ?.WithOrder(1) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + + private static void SetSignInSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(IdentitySettingNames.SignIn.RequireConfirmedEmail) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("SignIn", L("Settings:Identity.SignIn"), order: 2) + ?.WithOrder(0) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.SignIn.RequireEmailVerificationToRegister) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("SignIn", L("Settings:Identity.SignIn"), order: 2) + ?.WithOrder(1) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.SignIn.EnablePhoneNumberConfirmation) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("SignIn", L("Settings:Identity.SignIn"), order: 2) + ?.WithOrder(2) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("SignIn", L("Settings:Identity.SignIn"), order: 2) + ?.WithOrder(3) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + + private static void SetPasswordSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(IdentitySettingNames.Password.RequireDigit) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(0) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.RequiredLength) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(1) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.RequiredUniqueChars) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(2) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.RequireLowercase) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(3) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.RequireUppercase) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(4) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.RequireNonAlphanumeric) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(5) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.ForceUsersToPeriodicallyChangePassword) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(6) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.PasswordChangePeriodDays) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(7) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.EnablePreventPasswordReuse) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(8) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(IdentitySettingNames.Password.PreventPasswordReuseCount) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("Password", L("Settings:Identity.Password"), order: 4) + ?.WithOrder(9) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + + private static void SetOrganizationUnitSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(IdentitySettingNames.OrganizationUnit.MaxUserMembershipCount) + ?.WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + ?.WithParent("OrganizationUnit", L("Settings:Identity.OrganizationUnit"), order: 6) + ?.WithOrder(0) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj index 1efc41797..531f1ff36 100644 --- a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj +++ b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj @@ -24,6 +24,7 @@ + diff --git a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/en.json b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/en.json index 7a13975df..32dc74af3 100644 --- a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/en.json +++ b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/en.json @@ -28,6 +28,10 @@ "Notifications:DissolveGroup": "Dissolve group notification", "AddNewFriendBySearchId": "Add by account search", "WelcomeToApplicationFormUser": "User :{User} welcome to join us!", - "Messages:NewFriend": "I have added you as a friend, let's chat together!" + "Messages:NewFriend": "I have added you as a friend, let's chat together!", + "DisplayName:RecallExpirationTime": "Message revocation expiration time", + "Description:RecallExpirationTime": "Allow user to withdraw message time limit (minutes).", + "Settings:MessageService": "IM", + "Settings:MessageService.Messages": "Messages" } } \ No newline at end of file diff --git a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json index ba4233ca3..617fefb89 100644 --- a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json @@ -28,6 +28,10 @@ "Notifications:DissolveGroup": "群组解散通知", "AddNewFriendBySearchId": "通过账号搜索添加", "WelcomeToApplicationFormUser": "用户:{User} 欢迎您的加入!", - "Messages:NewFriend": "我已经添加您为好友,让我们一起聊天吧!" + "Messages:NewFriend": "我已经添加您为好友,让我们一起聊天吧!", + "DisplayName:RecallExpirationTime": "撤回消息过期时间", + "Description:RecallExpirationTime": "允许用户撤回消息时间限制(分).", + "Settings:MessageService": "即时通讯", + "Settings:MessageService.Messages": "消息设置" } } \ No newline at end of file diff --git a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Settings/MessageServiceSettingDefinitionProvider.cs b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Settings/MessageServiceSettingDefinitionProvider.cs index 20295a38f..502a884cd 100644 --- a/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Settings/MessageServiceSettingDefinitionProvider.cs +++ b/aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Settings/MessageServiceSettingDefinitionProvider.cs @@ -6,6 +6,7 @@ namespace LINGYUN.Abp.MessageService.Settings; public class MessageServiceSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "MessageService"; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -21,10 +22,13 @@ public class MessageServiceSettingDefinitionProvider : SettingDefinitionProvider ConfigurationSettingValueProvider.ProviderName, GlobalSettingValueProvider.ProviderName, TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:MessageService")) + .WithParent("Messages", L("Settings:MessageService.Messages")) + .WithValueType(ValueType.Number) ); } - protected ILocalizableString L(string name) + protected LocalizableString L(string name) { return LocalizableString.Create(name); } diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs index 6aaa905b8..d25aaaf40 100644 --- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Features; @@ -29,32 +28,32 @@ public class WebhookNotificationPublishProvider : NotificationPublishProvider return base.CanPublishAsync(notification, cancellationToken); } - protected async override Task PublishAsync(NotificationInfo notification, IEnumerable identifiers, CancellationToken cancellationToken = default) + protected async override Task PublishAsync(NotificationPublishContext context, CancellationToken cancellationToken = default) { using var scope = ServiceScopeFactory.CreateScope(); foreach (var contributor in Options.Value.Contributors) { - var context = new WebhookNotificationContext(scope.ServiceProvider, notification); + var webhookNotificationContext = new WebhookNotificationContext(scope.ServiceProvider, context.Notification); - await contributor.ContributeAsync(context); + await contributor.ContributeAsync(webhookNotificationContext); - if (!context.HasResolved()) + if (!webhookNotificationContext.HasResolved()) { Logger.LogWarning("The Webhook notifies the contributor: {0} that the Webhook data for the given notification: {1} cannot be parsed. Skip it.", - contributor.Name, notification.Name); + contributor.Name, context.Notification.Name); continue; } else { await WebhookPublisher.PublishAsync( - context.Webhook.WebhookName, - context.Webhook.Data, - notification.TenantId, - context.Webhook.SendExactSameData, - context.Webhook.Headers); + webhookNotificationContext.Webhook.WebhookName, + webhookNotificationContext.Webhook.Data, + context.Notification.TenantId, + webhookNotificationContext.Webhook.SendExactSameData, + webhookNotificationContext.Webhook.Headers); - Logger.LogDebug("The webhook: {webhookName} with contributor: {name} has successfully published!", context.Webhook.WebhookName, Name); + Logger.LogDebug("The webhook: {webhookName} with contributor: {name} has successfully published!", webhookNotificationContext.Webhook.WebhookName, Name); } } } diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN.Abp.SettingManagement.Application.csproj b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN.Abp.SettingManagement.Application.csproj index 4c22b00c7..cdf9bb431 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN.Abp.SettingManagement.Application.csproj +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN.Abp.SettingManagement.Application.csproj @@ -27,6 +27,7 @@ + diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/AbpSettingManagementApplicationModule.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/AbpSettingManagementApplicationModule.cs index 948f517ef..04bcf3254 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/AbpSettingManagementApplicationModule.cs +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/AbpSettingManagementApplicationModule.cs @@ -3,10 +3,12 @@ using LINGYUN.Abp.Account.OAuth; using LINGYUN.Abp.Account.OAuth.Localization; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Application; +using Volo.Abp.Emailing; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.SettingManagement; using Volo.Abp.SettingManagement.Localization; +using Volo.Abp.Timing; using Volo.Abp.VirtualFileSystem; using VoloAbpSettingManagementApplicationContractsModule = Volo.Abp.SettingManagement.AbpSettingManagementApplicationContractsModule; @@ -18,6 +20,9 @@ namespace LINGYUN.Abp.SettingManagement; typeof(VoloAbpSettingManagementApplicationContractsModule), typeof(AbpAccountApplicationContractsModule), typeof(AbpAccountOAuthModule), + typeof(AbpEmailingModule), + typeof(AbpTimingModule), + typeof(AbpLocalizationModule), typeof(AbpDddApplicationModule) )] public class AbpSettingManagementApplicationModule : AbpModule diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/en.json b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/en.json index a9618ab5f..ed59b05e1 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/en.json @@ -35,6 +35,14 @@ "SettingProviders:T": "Tenant", "SettingProviders:U": "User", "BasicInfo": "Basic", - "Properties": "Properties" + "Properties": "Properties", + "Settings:DefaultGroup": "Default Group", + "Settings:DefaultSetting": "Default Setting", + "Settings:System": "System", + "Settings:System.Language": "Language", + "Settings:System.Timing": "Timing", + "Settings:Emailing": "Emailing", + "Settings:Emailing.Default": "Default", + "Settings:Emailing.Smtp": "Smtp" } } \ No newline at end of file diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/zh-Hans.json index 36a1374a3..b8d6541c7 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/Localization/Resources/zh-Hans.json @@ -35,6 +35,14 @@ "SettingProviders:T": "租户", "SettingProviders:U": "用户", "BasicInfo": "基本", - "Properties": "属性" + "Properties": "属性", + "Settings:DefaultGroup": "未分组设置", + "Settings:DefaultSetting": "默认设置", + "Settings:System": "系统设置", + "Settings:System.Language": "语言", + "Settings:System.Timing": "时区", + "Settings:Emailing": "邮件设置", + "Settings:Emailing.Default": "默认配置", + "Settings:Emailing.Smtp": "Smtp配置" } } \ No newline at end of file diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppService.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppService.cs new file mode 100644 index 000000000..6a49c330a --- /dev/null +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppService.cs @@ -0,0 +1,62 @@ +using Microsoft.AspNetCore.Authorization; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SettingManagement; +using Volo.Abp.Settings; + +namespace LINGYUN.Abp.SettingManagement; + +[Authorize(AbpSettingManagementPermissions.Settings.Default)] +public class SettingV2AppService : SettingV2AppServiceBase, ISettingV2AppService +{ + public SettingV2AppService( + IDistributedEventBus eventBus, + ISettingManager settingManager, + ISettingDefinitionManager settingDefinitionManager) + : base(eventBus, settingManager, settingDefinitionManager) + { + } + + public async virtual Task GetAsync() + { + await CheckFeatureAsync(); + + var providerName = CurrentTenant.GetMultiTenancySide() == MultiTenancySides.Host + ? GlobalSettingValueProvider.ProviderName + : TenantSettingValueProvider.ProviderName; + var providerKey = CurrentTenant.GetMultiTenancySide() == MultiTenancySides.Host + ? null + : CurrentTenant.GetId().ToString(); + + return await GetAllForProviderAsync(providerName, providerKey); + } + + [Authorize(AbpSettingManagementPermissions.Settings.Manager)] + public async virtual Task SetAsync(UpdateSettingsDto input) + { + await CheckFeatureAsync(); + + var multiTenancySides = CurrentTenant.GetMultiTenancySide(); + foreach (var setting in input.Settings) + { + if (multiTenancySides == MultiTenancySides.Host) + { + await SettingManager.SetGlobalAsync(setting.Name, setting.Value); + } + else + { + await SettingManager.SetForTenantAsync(CurrentTenant.GetId(), setting.Name, setting.Value); + } + } + + CurrentUnitOfWork.OnCompleted(async () => + { + await EventBus.PublishAsync(new CurrentApplicationConfigurationCacheResetEventData()); + }); + + await CurrentUnitOfWork.SaveChangesAsync(); + } +} diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppServiceBase.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppServiceBase.cs new file mode 100644 index 000000000..3c7371af3 --- /dev/null +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingV2AppServiceBase.cs @@ -0,0 +1,165 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; +using Volo.Abp.SettingManagement; +using Volo.Abp.SettingManagement.Localization; +using Volo.Abp.Settings; +using ValueType = Volo.Abp.Settings.ValueType; + +namespace LINGYUN.Abp.SettingManagement; + +public abstract class SettingV2AppServiceBase : ApplicationService +{ + protected IDistributedEventBus EventBus { get; } + protected ISettingManager SettingManager { get; } + protected ISettingDefinitionManager SettingDefinitionManager { get; } + + protected SettingV2AppServiceBase( + IDistributedEventBus eventBus, + ISettingManager settingManager, + ISettingDefinitionManager settingDefinitionManager) + { + EventBus = eventBus; + SettingManager = settingManager; + SettingDefinitionManager = settingDefinitionManager; + + LocalizationResource = typeof(AbpSettingManagementResource); + } + + protected async virtual Task GetAllForProviderAsync(string providerName, string providerKey) + { + var result = new SettingGroupResult(); + + var settingDefines = await SettingDefinitionManager.GetAllAsync(); + + + SettingGroupDto CreateSettingGroup(SettingResourceDefinition resource) + { + return resource != null + ? new SettingGroupDto(resource.Localize(StringLocalizerFactory).Value) + : new SettingGroupDto(L["Settings:DefaultGroup"]); + } + SettingDto CreateSetting(SettingGroupDto groupDto, SettingResourceDefinition resource) + { + var settingDisplayName = resource != null + ? resource.Localize(StringLocalizerFactory).Value + : L["Settings:DefaultSetting"]; + return groupDto.AddSetting(settingDisplayName, settingDisplayName); + } + async Task IsEnabledSettingResource(SettingResourceDefinition resource) + { + if (resource?.RequiredFeatures != null) + { + var checkFeatures = await FeatureChecker.IsEnabledAsync(resource.RequiredFeatures); + if (!checkFeatures.Any(x => x.Value)) + { + return false; + } + } + if (resource?.RequiredPermissions != null && + !await AuthorizationService.IsGrantedAnyAsync(resource.RequiredPermissions)) + { + return false; + } + return true; + } + async Task IsEnabledSetting(SettingDefinition setting) + { + if (setting.Providers.Count > 0 && !setting.Providers.Any(provider => provider == providerName)) + { + return false; + } + var requiredFeatures = setting.GetRequiredFeatures(); + if (requiredFeatures.Any()) + { + var checkFeatures = await FeatureChecker.IsEnabledAsync(requiredFeatures.ToArray()); + if (!checkFeatures.Any(x => x.Value)) + { + return false; + } + } + var requiredPermissions = setting.GetRequiredPermissions(); + if (requiredPermissions.Any() && + !await AuthorizationService.IsGrantedAnyAsync(requiredPermissions.ToArray())) + { + return false; + } + return true; + } + + foreach (var settingGroups in settingDefines.GroupBy(x => x.GetGroupOrNull()).OrderBy(x => x.Key?.Order ?? 9999)) + { + if (!await IsEnabledSettingResource(settingGroups.Key)) + { + continue; + } + var groupDto = CreateSettingGroup(settingGroups.Key); + foreach (var settings in settingGroups.GroupBy(x => x.GetParentOrNull()).OrderBy(x => x.Key?.Order ?? 9999)) + { + if (!await IsEnabledSettingResource(settings.Key)) + { + continue; + } + var settingDto = CreateSetting(groupDto, settings.Key); + + foreach (var setting in settings) + { + if (!await IsEnabledSetting(setting)) + { + continue; + } + var valueType = setting.GetValueTypeOrDefault(); + + var settingDetailsDto = settingDto.AddDetail( + await SettingDefinitionManager.GetAsync(setting.Name), + StringLocalizerFactory, + await SettingManager.GetOrNullAsync(setting.Name, providerName, providerKey), + valueType, + providerName); + + if (valueType == ValueType.Option) + { + var options = setting.GetOptions(); + settingDetailsDto.AddOptions(options.Select(option => new OptionDto(option.Name, option.Value))); + } + + var slot = setting.GetSlotOrNull(); + if (!slot.IsNullOrWhiteSpace()) + { + settingDetailsDto.WithSlot(slot); + } + + var requiredFeatures = setting.GetRequiredFeatures(); + if (requiredFeatures.Any()) + { + settingDetailsDto.RequiredFeature(requiredFeatures.ToArray()); + } + + var requiredPermissions = setting.GetRequiredPermissions(); + if (requiredPermissions.Any()) + { + settingDetailsDto.RequiredPermission(requiredPermissions.ToArray()); + } + } + + if (settingDto.Details.Count == 0) + { + groupDto.Settings.Remove(settingDto); + } + } + + result.AddGroup(groupDto); + } + + return result; + } + + protected async virtual Task CheckFeatureAsync() + { + await FeatureChecker.CheckEnabledAsync(SettingManagementFeatures.Enable); + } +} diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/UserSettingV2AppService.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/UserSettingV2AppService.cs new file mode 100644 index 000000000..33763342d --- /dev/null +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/UserSettingV2AppService.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.Authorization; +using System.Threading.Tasks; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SettingManagement; +using Volo.Abp.Settings; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.SettingManagement; + +[Authorize] +public class UserSettingV2AppService : SettingV2AppServiceBase, IUserSettingV2AppService +{ + public UserSettingV2AppService( + IDistributedEventBus eventBus, + ISettingManager settingManager, + ISettingDefinitionManager settingDefinitionManager) + : base(eventBus, settingManager, settingDefinitionManager) + { + } + + public async virtual Task GetAsync() + { + await CheckFeatureAsync(); + + return await GetAllForProviderAsync(UserSettingValueProvider.ProviderName, CurrentUser.GetId().ToString()); + } + + public async virtual Task SetAsync(UpdateSettingsDto input) + { + await CheckFeatureAsync(); + + foreach (var setting in input.Settings) + { + await SettingManager.SetForCurrentUserAsync(setting.Name, setting.Value); + } + } +} diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingController.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingController.cs index 09064a146..151109253 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingController.cs +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingController.cs @@ -1,59 +1,59 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.AspNetCore.Mvc; - -namespace LINGYUN.Abp.SettingManagement; - -[RemoteService(Name = AbpSettingManagementRemoteServiceConsts.RemoteServiceName)] -[Area("SettingManagement")] -[Route("api/setting-management/settings")] -public class SettingController : AbpControllerBase, ISettingAppService, ISettingTestAppService -{ - private readonly ISettingAppService _settingAppService; - private readonly ISettingTestAppService _settingTestAppService; - public SettingController( - ISettingAppService settingAppService, - ISettingTestAppService settingTestAppService) - { +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.SettingManagement; + +[RemoteService(Name = AbpSettingManagementRemoteServiceConsts.RemoteServiceName)] +[Area("SettingManagement")] +[Route("api/setting-management/settings")] +public class SettingController : AbpControllerBase, ISettingAppService, ISettingTestAppService +{ + private readonly ISettingAppService _settingAppService; + private readonly ISettingTestAppService _settingTestAppService; + public SettingController( + ISettingAppService settingAppService, + ISettingTestAppService settingTestAppService) + { _settingAppService = settingAppService; _settingTestAppService = settingTestAppService; - } - - [HttpPut] - [Route("change-current-tenant")] - public async virtual Task SetCurrentTenantAsync(UpdateSettingsDto input) - { - await _settingAppService.SetCurrentTenantAsync(input); - } - - [HttpPut] - [Route("change-global")] - public async virtual Task SetGlobalAsync(UpdateSettingsDto input) - { - await _settingAppService.SetGlobalAsync(input); - } - - [HttpGet] - [Route("by-global")] - public async virtual Task GetAllForGlobalAsync() - { - return await _settingAppService.GetAllForGlobalAsync(); - } - - [HttpGet] - [Route("by-current-tenant")] - public async virtual Task GetAllForCurrentTenantAsync() - { - return await _settingAppService.GetAllForCurrentTenantAsync(); - } - - [HttpPost] - [Authorize] - [Route("send-test-email")] + } + + [HttpPut] + [Route("change-current-tenant")] + public async virtual Task SetCurrentTenantAsync(UpdateSettingsDto input) + { + await _settingAppService.SetCurrentTenantAsync(input); + } + + [HttpPut] + [Route("change-global")] + public async virtual Task SetGlobalAsync(UpdateSettingsDto input) + { + await _settingAppService.SetGlobalAsync(input); + } + + [HttpGet] + [Route("by-global")] + public async virtual Task GetAllForGlobalAsync() + { + return await _settingAppService.GetAllForGlobalAsync(); + } + + [HttpGet] + [Route("by-current-tenant")] + public async virtual Task GetAllForCurrentTenantAsync() + { + return await _settingAppService.GetAllForCurrentTenantAsync(); + } + + [HttpPost] + [Authorize] + [Route("send-test-email")] public async virtual Task SendTestEmailAsync(SendTestEmailInput input) { await _settingTestAppService.SendTestEmailAsync(input); - } -} + } +} diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingV2Controller.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingV2Controller.cs new file mode 100644 index 000000000..b35bbc8cd --- /dev/null +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/SettingV2Controller.cs @@ -0,0 +1,26 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.SettingManagement; + +[RemoteService(Name = AbpSettingManagementRemoteServiceConsts.RemoteServiceName)] +[ApiVersion("2")] +[Area("SettingManagement")] +[Route("api/v{version}/setting-management/settings")] +public class SettingV2Controller(ISettingV2AppService _service) : AbpControllerBase, ISettingV2AppService +{ + [HttpGet] + public virtual Task GetAsync() + { + return _service.GetAsync(); + } + + [HttpPut] + public virtual Task SetAsync(UpdateSettingsDto input) + { + return _service.SetAsync(input); + } +} diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/UserSettingV2Controller.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/UserSettingV2Controller.cs new file mode 100644 index 000000000..788bfc1c0 --- /dev/null +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.HttpApi/LINGYUN/Abp/SettingManagement/UserSettingV2Controller.cs @@ -0,0 +1,26 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.SettingManagement; + +[RemoteService(Name = AbpSettingManagementRemoteServiceConsts.RemoteServiceName)] +[ApiVersion("2")] +[Area("SettingManagement")] +[Route("api/v{version}/setting-management/my-settings")] +public class UserSettingV2Controller(IUserSettingV2AppService _service) : AbpControllerBase, IUserSettingV2AppService +{ + [HttpGet] + public virtual Task GetAsync() + { + return _service.GetAsync(); + } + + [HttpPut] + public virtual Task SetAsync(UpdateSettingsDto input) + { + return _service.SetAsync(input); + } +} From e309df5c01c4967fe5ef1372d005d3f8d200c061 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 16:29:01 +0800 Subject: [PATCH 31/40] feat: Add Account Setting Group --- .../AdminServiceModule.cs | 2 + ...NGYUN.Abp.MicroService.AdminService.csproj | 1 + .../SystemGroupSettingDefinitionProvider.cs | 258 ++++++++++++++++++ .../AccountSettingDefinitionProvider.cs | 26 +- 4 files changed, 279 insertions(+), 8 deletions(-) create mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/SystemGroupSettingDefinitionProvider.cs diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/AdminServiceModule.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/AdminServiceModule.cs index d5198f7e1..a751ca3fc 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/AdminServiceModule.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/AdminServiceModule.cs @@ -4,6 +4,7 @@ using LINGYUN.Abp.AspNetCore.Mvc.Localization; using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; using LINGYUN.Abp.Auditing; using LINGYUN.Abp.AuditLogging.Elasticsearch; +using LINGYUN.Abp.BlobManagement.SettingManagement; using LINGYUN.Abp.CachingManagement; using LINGYUN.Abp.CachingManagement.StackExchangeRedis; using LINGYUN.Abp.Claims.Mapping; @@ -58,6 +59,7 @@ namespace LINGYUN.Abp.MicroService.AdminService; typeof(AbpTencentCloudSettingManagementModule), // typeof(AbpWeChatSettingManagementModule), typeof(AbpWxPusherSettingManagementModule), + typeof(AbpBlobManagementSettingManagementModule), typeof(AbpSettingManagementApplicationModule), typeof(AbpSettingManagementHttpApiModule), diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/LINGYUN.Abp.MicroService.AdminService.csproj b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/LINGYUN.Abp.MicroService.AdminService.csproj index f6010ebc6..a7916e170 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/LINGYUN.Abp.MicroService.AdminService.csproj +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/LINGYUN.Abp.MicroService.AdminService.csproj @@ -55,6 +55,7 @@ + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/SystemGroupSettingDefinitionProvider.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/SystemGroupSettingDefinitionProvider.cs new file mode 100644 index 000000000..e964206d8 --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/SystemGroupSettingDefinitionProvider.cs @@ -0,0 +1,258 @@ +using LINGYUN.Abp.SettingManagement; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.Emailing; +using Volo.Abp.Localization; +using Volo.Abp.SettingManagement; +using Volo.Abp.SettingManagement.Localization; +using Volo.Abp.Settings; +using Volo.Abp.Timing; +using ValueType = Volo.Abp.Settings.ValueType; + +namespace LINGYUN.Abp.MicroService.AdminService; + +public class SystemGroupSettingDefinitionProvider : SettingDefinitionProvider +{ + private const string GroupName = "System"; + + protected ITimezoneProvider TimezoneProvider { get; } + protected AbpLocalizationOptions LocalizationOptions { get; } + protected IStringLocalizerFactory StringLocalizerFactory { get; } + + public SystemGroupSettingDefinitionProvider( + ITimezoneProvider timezoneProvider, + IStringLocalizerFactory stringLocalizerFactory, + IOptions localizationOptions) + { + TimezoneProvider = timezoneProvider; + StringLocalizerFactory = stringLocalizerFactory; + LocalizationOptions = localizationOptions.Value; + } + + public override void Define(ISettingDefinitionContext context) + { + SetSystemSettingGroup(context); + SetEmailSettingGroup(context); + } + + private void SetSystemSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(LocalizationSettingNames.DefaultLanguage) + ?.WithGroup(GroupName, L("Settings:System"), order: 0) + ?.WithParent("Language", L("Settings:System.Language"), order: 0) + ?.WithOrder(0) + ?.WithOptions(LocalizationOptions.Languages.Select(l => new NameValue(l.DisplayName, l.CultureName))) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + + var timezoneSetting = context.GetOrNull(TimingSettingNames.TimeZone); + if (timezoneSetting != null) + { + var stringLocalizer = StringLocalizerFactory.Create(); + var timezones = TimeZoneHelper.GetTimezones(TimezoneProvider.GetIanaTimezones()); + timezones.Insert(0, new NameValue + { + Name = stringLocalizer["DefaultTimeZone"], + Value = "Unspecified" + }); + + timezoneSetting + .WithGroup( + GroupName, + L("Settings:System"), + order: 0, + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.TimeZone]) + .WithParent("Timing", L("Settings:System.Timing"), order: 0) + .WithOrder(1) + .WithOptions(timezones) + .ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + } + + private static void SetEmailSettingGroup(ISettingDefinitionContext context) + { + context.GetOrNull(EmailSettingNames.DefaultFromAddress) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Default", + L("Settings:Emailing.Default"), + order: 0) + ?.WithOrder(0) + ?.WithValueType(ValueType.String) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.DefaultFromDisplayName) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Default", + L("Settings:Emailing.Default"), + order: 0) + ?.WithOrder(1) + ?.WithValueType(ValueType.String) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + + context.GetOrNull(EmailSettingNames.Smtp.Domain) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(0) + ?.WithValueType(ValueType.String) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.Smtp.Host) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(1) + ?.WithValueType(ValueType.String) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.Smtp.Port) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(2) + ?.WithValueType(ValueType.Number) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.Smtp.UserName) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(3) + ?.WithValueType(ValueType.String) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.Smtp.Password) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(4) + ?.WithValueType(ValueType.String) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.Smtp.EnableSsl) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(5) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + context.GetOrNull(EmailSettingNames.Smtp.UseDefaultCredentials) + ?.WithGroup( + "Emailing", + L("Settings:Emailing"), + order: 1, + requiredFeatures: [SettingManagementFeatures.Enable, SettingManagementFeatures.AllowChangingEmailSettings], + requiredPermissions: [Volo.Abp.SettingManagement.SettingManagementPermissions.Emailing]) + ?.WithParent( + "Smtp", + L("Settings:Emailing.Smtp"), + order: 1, + requiredPermissions: [AbpSettingManagementPermissions.Settings.Manager]) + ?.WithOrder(6) + ?.WithValueType(ValueType.Boolean) + ?.ReplaceProviders( + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName); + } + + public static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Settings/AccountSettingDefinitionProvider.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Settings/AccountSettingDefinitionProvider.cs index 40b28f7d5..54476f79e 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Settings/AccountSettingDefinitionProvider.cs +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Settings/AccountSettingDefinitionProvider.cs @@ -8,6 +8,8 @@ namespace LY.MicroService.BackendAdmin.Settings; // 后台管理项目不引用 Volo.Abp.Account.Application模块,只能自建一个配置 public class AccountSettingDefinitionProvider : SettingDefinitionProvider { + private const string GroupName = "Identity"; + private const int GroupOrder = 10; public override void Define(ISettingDefinitionContext context) { context.Add( @@ -18,10 +20,14 @@ public class AccountSettingDefinitionProvider : SettingDefinitionProvider L("Description:Abp.Account.IsSelfRegistrationEnabled"), isVisibleToClients: true) .WithProviders( - DefaultValueSettingValueProvider.ProviderName, - ConfigurationSettingValueProvider.ProviderName, - GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName) + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("Account", L("Settings:Identity.Account"), order: 0) + .WithOrder(1) + .WithValueType(ValueType.Boolean) ); context.Add( @@ -32,10 +38,14 @@ public class AccountSettingDefinitionProvider : SettingDefinitionProvider L("Description:Abp.Account.EnableLocalLogin"), isVisibleToClients: true) .WithProviders( - DefaultValueSettingValueProvider.ProviderName, - ConfigurationSettingValueProvider.ProviderName, - GlobalSettingValueProvider.ProviderName, - TenantSettingValueProvider.ProviderName) + DefaultValueSettingValueProvider.ProviderName, + ConfigurationSettingValueProvider.ProviderName, + GlobalSettingValueProvider.ProviderName, + TenantSettingValueProvider.ProviderName) + .WithGroup(GroupName, L("Settings:Identity"), GroupOrder) + .WithParent("Account", L("Settings:Identity.Account"), order: 0) + .WithOrder(0) + .WithValueType(ValueType.Boolean) ); } From 5b8f1ee059eed4a0f0e6c0672690b76429fe3043 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 16:48:22 +0800 Subject: [PATCH 32/40] feat: Setting page using the v2 interface --- .../account/src/components/UserLinkModal.vue | 6 ++++ .../src/components/features/FeatureModal.vue | 2 +- .../permissions/PermissionModal.vue | 2 +- .../vben5/packages/@abp/settings/package.json | 1 + .../settings/src/api/useDefinitionsApi.ts | 2 +- .../@abp/settings/src/api/useSettingsApi.ts | 30 +++++++++++++++++-- .../src/components/settings/SettingForm.vue | 22 +++++++++----- .../src/components/settings/SystemSetting.vue | 21 +++---------- .../components/properties/PropertyTable.vue | 7 ++--- 9 files changed, 60 insertions(+), 33 deletions(-) diff --git a/apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue b/apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue index 59a0547c9..0b16737c7 100644 --- a/apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue +++ b/apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue @@ -44,6 +44,12 @@ const gridOptions: VxeGridProps = { { align: 'left', field: 'linkUserName', + formatter: ({ row }) => { + if (row.linkTenantName) { + return `${row.linkTenantName}/${row.linkUserName}`; + } + return row.linkUserName; + }, sortable: true, title: $t('AbpAccount.DisplayName:LinkUserName'), }, diff --git a/apps/vben5/packages/@abp/features/src/components/features/FeatureModal.vue b/apps/vben5/packages/@abp/features/src/components/features/FeatureModal.vue index 57bd213f5..0d3ec8e92 100644 --- a/apps/vben5/packages/@abp/features/src/components/features/FeatureModal.vue +++ b/apps/vben5/packages/@abp/features/src/components/features/FeatureModal.vue @@ -269,7 +269,7 @@ async function onSubmit() { + diff --git a/apps/vben5/packages/@abp/settings/src/components/settings/SystemSetting.vue b/apps/vben5/packages/@abp/settings/src/components/settings/SystemSetting.vue index 25d0d2cc0..c1c144fe7 100644 --- a/apps/vben5/packages/@abp/settings/src/components/settings/SystemSetting.vue +++ b/apps/vben5/packages/@abp/settings/src/components/settings/SystemSetting.vue @@ -6,7 +6,7 @@ import { ref } from 'vue'; import { useVbenModal } from '@vben/common-ui'; import { $t } from '@vben/locales'; -import { isEmail, useAbpStore } from '@abp/core'; +import { isEmail } from '@abp/core'; import { FeatureModal } from '@abp/features'; import { Button, Form, InputSearch, message, Modal } from 'ant-design-vue'; @@ -19,14 +19,7 @@ defineOptions({ const FormItem = Form.Item; -const abpStore = useAbpStore(); -const { - getGlobalSettingsApi, - getTenantSettingsApi, - sendTestEmailApi, - setGlobalSettingsApi, - setTenantSettingsApi, -} = useSettingsApi(); +const { getSettingsApi, setSettingsApi, sendTestEmailApi } = useSettingsApi(); const [HostFeatureModal, featureModalApi] = useVbenModal({ connectedComponent: FeatureModal, }); @@ -34,18 +27,12 @@ const [HostFeatureModal, featureModalApi] = useVbenModal({ const sending = ref(false); async function onGet() { - const api = abpStore.application?.currentTenant.isAvailable - ? getTenantSettingsApi - : getGlobalSettingsApi; - const { items } = await api(); + const { items } = await getSettingsApi(); return items; } async function onSubmit(input: SettingsUpdateInput) { - const api = abpStore.application?.currentTenant.isAvailable - ? setTenantSettingsApi - : setGlobalSettingsApi; - await api(input); + await setSettingsApi(input); } async function onSendMail(email: string) { diff --git a/apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue b/apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue index 6a377f570..1a7d9e1f2 100644 --- a/apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue +++ b/apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue @@ -46,7 +46,6 @@ const getTableColumns = computed((): TableColumnsType => { { align: 'left', dataIndex: 'key', - fixed: 'left', width: 100, title: $t('component.extra_property_dictionary.key'), customRender: (opt) => { @@ -58,8 +57,8 @@ const getTableColumns = computed((): TableColumnsType => { { align: 'left', dataIndex: 'value', - fixed: 'left', - minWidth: 150, + width: 500, + ellipsis: true, title: $t('component.extra_property_dictionary.value'), }, ]; @@ -74,7 +73,7 @@ const getTableColumns = computed((): TableColumnsType => { fixed: 'right', key: 'action', title: $t('component.extra_property_dictionary.actions.title'), - width: 150, + width: 200, }, ] as TableColumnsType)), ]; From edab96e209a4d6b7869b2be609e78531903530c3 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 16:54:30 +0800 Subject: [PATCH 33/40] feat: Resolve potential anomalies in option values --- .../Volo/Abp/Settings/SettingDefinitionExtensions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs index e273ad654..e85e8f045 100644 --- a/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs +++ b/aspnet-core/framework/settings/LINGYUN.Abp.Settings/Volo/Abp/Settings/SettingDefinitionExtensions.cs @@ -227,7 +227,8 @@ public static class SettingDefinitionExtensions public static IEnumerable> GetOptions(this SettingDefinition definition) { if (definition.TryGetArrayProperties(OptionNameKey, out var optionNames) && - definition.TryGetArrayProperties(OptionValueKey, out var optionValues)) + definition.TryGetArrayProperties(OptionValueKey, out var optionValues) && + optionNames.Length == optionValues.Length) { return optionNames.Select((name, index) => { From b49790ed88dd03f2f83f9697b93e3d589e555ecc Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 16:58:53 +0800 Subject: [PATCH 34/40] feat: Optimize dynamic localization initialization --- .../DynamicLocalizationChangedEto.cs | 5 + .../DynamicLocalizationInitializerEto.cs | 53 +++ .../ResourceChangedEto.cs | 11 + .../AbpLocalizationManagementDomainModule.cs | 1 + .../AbpLocalizationManagementOptions.cs | 4 + .../DynamicLocalizationChangedEventHandler.cs | 51 +++ ...DynamicLocalizationInitializerCacheItem.cs | 73 ++++ ...micLocalizationInitializerEeventHandler.cs | 379 ++++++++++++++++++ .../ExternalLocalizationStoreCache.cs | 112 +----- .../ExternalLocalizationTextStoreCache.cs | 71 +--- .../IExternalLocalizationStoreCache.cs | 2 - .../IExternalLocalizationTextStoreCache.cs | 2 - .../LocalizationResourceCacheInvalidator.cs | 36 -- .../External/LocalizationResourceCacheItem.cs | 5 + .../IResourceRepository.cs | 3 + .../LocalizationLanguageCacheInvalidator.cs | 21 - .../LocalizationLanguageStoreCache.cs | 51 +-- .../LocalizationTextCacheInvalidator.cs | 32 -- .../LocalizationTextStoreCache.cs | 61 +-- .../StaticLocalizationSaver.cs | 344 +++------------- .../EfCoreResourceRepository.cs | 7 + 21 files changed, 682 insertions(+), 642 deletions(-) create mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEto.cs create mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEto.cs create mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/ResourceChangedEto.cs create mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEventHandler.cs create mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerCacheItem.cs create mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEeventHandler.cs delete mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs delete mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheInvalidator.cs delete mode 100644 aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEto.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEto.cs new file mode 100644 index 000000000..1463c9bf3 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEto.cs @@ -0,0 +1,5 @@ +namespace LINGYUN.Abp.LocalizationManagement; + +public class DynamicLocalizationChangedEto +{ +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEto.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEto.cs new file mode 100644 index 000000000..1d6fc5dab --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEto.cs @@ -0,0 +1,53 @@ +namespace LINGYUN.Abp.LocalizationManagement; + +public abstract class DynamicLocalizationInitializerEto +{ + public string[] Keys { get; set; } + protected DynamicLocalizationInitializerEto() + { + + } + + protected DynamicLocalizationInitializerEto(string[] keys) + { + Keys = keys; + } +} + +public class DynamicLanguageInitializerEto : DynamicLocalizationInitializerEto +{ + public DynamicLanguageInitializerEto() + { + + } + + public DynamicLanguageInitializerEto(string[] keys) : base(keys) + { + } +} + + +public class DynamicResourceInitializerEto : DynamicLocalizationInitializerEto +{ + public DynamicResourceInitializerEto() + { + + } + + public DynamicResourceInitializerEto(string[] keys) : base(keys) + { + } +} + + +public class DynamicTextInitializerEto : DynamicLocalizationInitializerEto +{ + public DynamicTextInitializerEto() + { + + } + + public DynamicTextInitializerEto(string[] keys) : base(keys) + { + } +} \ No newline at end of file diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/ResourceChangedEto.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/ResourceChangedEto.cs new file mode 100644 index 000000000..a12b250b3 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/ResourceChangedEto.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.LocalizationManagement; + +[Serializable] +public class ResourceChangedEto +{ + public List Resources { get; set; } + public List Cultures { get; set; } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs index 9bcb740ca..306129ae6 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs @@ -20,6 +20,7 @@ namespace LINGYUN.Abp.LocalizationManagement; public class AbpLocalizationManagementDomainModule : AbpModule { private readonly CancellationTokenSource _cancellationTokenSource = new(); + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddMapperlyObjectMapper(); diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementOptions.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementOptions.cs index c9fe5f701..ebf73618f 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementOptions.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementOptions.cs @@ -6,6 +6,10 @@ public class AbpLocalizationManagementOptions /// 保存本地化文本到数据库 /// public bool SaveStaticLocalizationsToDatabase { get; set; } = true; + /// + /// 是否动态本地化文本初始化节点 + /// + public bool IsDynamicLocalizationInitializerHost { get; set; } = false; public AbpLocalizationManagementOptions() { diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEventHandler.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEventHandler.cs new file mode 100644 index 000000000..9eee09c4c --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationChangedEventHandler.cs @@ -0,0 +1,51 @@ +using LINGYUN.Abp.LocalizationManagement.External; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; + +namespace LINGYUN.Abp.LocalizationManagement; + +public class DynamicLocalizationChangedEventHandler : + IDistributedEventHandler, + ITransientDependency +{ + protected IDistributedCache ResourcesCache { get; } + protected IDistributedCache LanguageCache { get; } + + protected IExternalLocalizationTextStoreCache ExternalLocalizationTextStoreCache { get; } + protected ILocalizationTextStoreCache LocalizationTextStoreCache { get; } + + public DynamicLocalizationChangedEventHandler( + IDistributedCache resourcesCache, + IDistributedCache languageCache, + IExternalLocalizationTextStoreCache externalLocalizationTextStoreCache, + ILocalizationTextStoreCache localizationTextStoreCache) + { + ResourcesCache = resourcesCache; + LanguageCache = languageCache; + ExternalLocalizationTextStoreCache = externalLocalizationTextStoreCache; + LocalizationTextStoreCache = localizationTextStoreCache; + } + + public async virtual Task HandleEventAsync(DynamicLocalizationChangedEto eventData) + { + var resourcesCacheItem = await ResourcesCache.GetAsync(LocalizationResourcesCacheItem.CacheKey); + var languagesCacheItem = await LanguageCache.GetAsync(LocalizationLanguageCacheItem.CacheKey); + + foreach (var language in languagesCacheItem.Languages) + { + foreach (var resource in resourcesCacheItem.Resources) + { + if (ExternalLocalizationTextStoreCache is ExternalLocalizationTextStoreCache storeCache) + { + await storeCache.UpdateCache(resource.Name, language.CultureName); + } + if (LocalizationTextStoreCache is LocalizationTextStoreCache textStoreCache) + { + await textStoreCache.UpdateCache(resource.Name, language.CultureName); + } + } + } + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerCacheItem.cs new file mode 100644 index 000000000..b9325f9b8 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerCacheItem.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.LocalizationManagement; + +[Serializable] +[IgnoreMultiTenancy] +[CacheName("DynamicLanguageInitializer")] +public class DynamicLanguageInitializerCacheItem +{ + public string CultureName { get; set; } + public string UiCultureName { get; set; } + public string DisplayName { get; set; } + public string TwoLetterISOLanguageName { get; set; } + public DynamicLanguageInitializerCacheItem() + { + } + public DynamicLanguageInitializerCacheItem( + string cultureName, + string uiCultureName, + string displayName, + string twoLetterISOLanguageName) + { + CultureName = cultureName; + UiCultureName = uiCultureName; + DisplayName = displayName; + TwoLetterISOLanguageName = twoLetterISOLanguageName; + } +} + +[Serializable] +[IgnoreMultiTenancy] +[CacheName("DynamicResourceInitializer")] +public class DynamicResourceInitializerCacheItem +{ + public string ResourceName { get; set; } + public string DefaultCultureName { get; set; } + public DynamicResourceInitializerCacheItem() + { + } + public DynamicResourceInitializerCacheItem( + string resourceName, + string defaultCultureName) + { + ResourceName = resourceName; + DefaultCultureName = defaultCultureName; + } +} + +[Serializable] +[IgnoreMultiTenancy] +[CacheName("DynamicTextInitializer")] +public class DynamicTextInitializerCacheItem +{ + public string ResourceName { get; set; } + public string CultureName { get; set; } + public Dictionary Texts { get; set; } + public DynamicTextInitializerCacheItem() + { + Texts = new Dictionary(); + } + public DynamicTextInitializerCacheItem( + string resourceName, + string cultureName, + Dictionary texts) + { + ResourceName = resourceName; + CultureName = cultureName; + Texts = texts; + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEeventHandler.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEeventHandler.cs new file mode 100644 index 000000000..ae2bf0377 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/DynamicLocalizationInitializerEeventHandler.cs @@ -0,0 +1,379 @@ +using LINGYUN.Abp.LocalizationManagement.External; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Guids; +using Volo.Abp.Localization; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.LocalizationManagement; + +public class DynamicLocalizationInitializerEeventHandler : + IDistributedEventHandler, + IDistributedEventHandler, + IDistributedEventHandler, + ITransientDependency +{ + public ILogger Logger { protected get; set; } + + protected IDistributedCache ResourceCache { get; } + protected IDistributedCache ResourcesCache { get; } + protected IDistributedCache LanguageCache { get; } + protected IDistributedCache LocalizationTextCache { get; } + + protected IDistributedCache DynamicLanguageCache { get; } + protected IDistributedCache DynamicResourceCache { get; } + protected IDistributedCache DynamicTextCache { get; } + + protected AbpLocalizationManagementOptions LocalizationManagementOptions { get; } + + protected IGuidGenerator GuidGenerator { get; } + protected IAbpDistributedLock DistributedLock { get; } + protected IDistributedEventBus DistributedEventBus { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + protected ILanguageRepository LanguageRepository { get; } + protected IResourceRepository ResourceRepository { get; } + protected ITextRepository TextRepository { get; } + + public DynamicLocalizationInitializerEeventHandler( + IDistributedCache resourceCache, + IDistributedCache resourcesCache, + IDistributedCache languageCache, + IDistributedCache localizationTextCache, + IDistributedCache dynamicLanguageCache, + IDistributedCache dynamicResourceCache, + IDistributedCache dynamicTextCache, + IOptions localizationManagementOptions, + IGuidGenerator guidGenerator, + IAbpDistributedLock distributedLock, + IDistributedEventBus distributedEventBus, + IUnitOfWorkManager unitOfWorkManager, + ILanguageRepository languageRepository, + IResourceRepository resourceRepository, + ITextRepository textRepository) + { + ResourceCache = resourceCache; + ResourcesCache = resourcesCache; + LanguageCache = languageCache; + LocalizationTextCache = localizationTextCache; + DynamicLanguageCache = dynamicLanguageCache; + DynamicResourceCache = dynamicResourceCache; + DynamicTextCache = dynamicTextCache; + LocalizationManagementOptions = localizationManagementOptions.Value; + GuidGenerator = guidGenerator; + DistributedLock = distributedLock; + DistributedEventBus = distributedEventBus; + UnitOfWorkManager = unitOfWorkManager; + LanguageRepository = languageRepository; + ResourceRepository = resourceRepository; + TextRepository = textRepository; + + Logger = NullLogger.Instance; + } + + public async virtual Task HandleEventAsync(DynamicLanguageInitializerEto eventData) + { + if (!LocalizationManagementOptions.SaveStaticLocalizationsToDatabase || + !LocalizationManagementOptions.IsDynamicLocalizationInitializerHost) + { + return; + } + + Logger.LogDebug("Waiting to acquire the distributed lock for saving static languages..."); + + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + $"{nameof(DynamicLocalizationInitializerEeventHandler)}_{nameof(DynamicLanguageInitializerEto)}", + TimeSpan.FromSeconds(5)); + if (applicationLockHandle == null) + { + throw new AbpException("Failed to acquire the initialization lock for the localization languages!"); + } + + using var unitOfWork = UnitOfWorkManager.Begin(true, true); + + var cacheItems = await DynamicLanguageCache.GetManyAsync(eventData.Keys); + + await SaveLanguagesAsync(cacheItems.Select(kv => kv.Value).ToArray()); + + Logger.LogInformation("Refresh language cache items."); + await RefreshLanguagesCacheAsync(); + + await DynamicLanguageCache.RemoveManyAsync(eventData.Keys); + + await DistributedEventBus.PublishAsync(new DynamicLocalizationChangedEto()); + + await unitOfWork.CompleteAsync(); + + Logger.LogInformation("Completed to save static languages."); + } + + public async virtual Task HandleEventAsync(DynamicResourceInitializerEto eventData) + { + if (!LocalizationManagementOptions.SaveStaticLocalizationsToDatabase || + !LocalizationManagementOptions.IsDynamicLocalizationInitializerHost) + { + return; + } + + Logger.LogDebug("Waiting to acquire the distributed lock for saving static resources..."); + + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + $"{nameof(DynamicLocalizationInitializerEeventHandler)}_{nameof(DynamicResourceInitializerEto)}", + TimeSpan.FromSeconds(5)); + if (applicationLockHandle == null) + { + throw new AbpException("Failed to acquire the initialization lock for the localization resources!"); + } + + using var unitOfWork = UnitOfWorkManager.Begin(true, true); + + var cacheItems = await DynamicResourceCache.GetManyAsync(eventData.Keys); + + await SaveResourcesAsync(cacheItems.Select(kv => kv.Value).ToArray()); + + Logger.LogInformation("Refresh resource cache items."); + await RefreshResourcesCacheAsync(); + + await DynamicResourceCache.RemoveManyAsync(eventData.Keys); + + await DistributedEventBus.PublishAsync(new DynamicLocalizationChangedEto()); + + await unitOfWork.CompleteAsync(); + + Logger.LogInformation("Completed to save static resources."); + } + + public async virtual Task HandleEventAsync(DynamicTextInitializerEto eventData) + { + if (!LocalizationManagementOptions.SaveStaticLocalizationsToDatabase || + !LocalizationManagementOptions.IsDynamicLocalizationInitializerHost) + { + return; + } + + Logger.LogDebug("Waiting to acquire the distributed lock for saving static texts..."); + + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + $"{nameof(DynamicLocalizationInitializerEeventHandler)}_{nameof(DynamicTextInitializerEto)}", + TimeSpan.FromSeconds(5)); + if (applicationLockHandle == null) + { + throw new AbpException("Failed to acquire the initialization lock for the localization texts!"); + } + + using var unitOfWork = UnitOfWorkManager.Begin(true, true); + + var cacheItemDics = await DynamicTextCache.GetManyAsync(eventData.Keys); + var cacheItems = cacheItemDics.Select(kv => kv.Value).ToArray(); + + await SaveTextsAsync(cacheItems); + + Logger.LogInformation("Refresh text cache items."); + await RefreshTextsCacheAsync(cacheItems); + + await DynamicResourceCache.RemoveManyAsync(eventData.Keys); + + await DistributedEventBus.PublishAsync(new DynamicLocalizationChangedEto()); + + await unitOfWork.CompleteAsync(); + + Logger.LogInformation("Completed to save static texts."); + } + + private async Task SaveLanguagesAsync(DynamicLanguageInitializerCacheItem[] cacheItems) + { + var newLanguages = new List(); + var updateLanguages = new List(); + var existsLanguages = await LanguageRepository.GetListAsync(); + foreach (var cacheItem in cacheItems) + { + var existsLanguage = existsLanguages.FirstOrDefault(x => x.CultureName == cacheItem.CultureName); + if (existsLanguage == null) + { + newLanguages.Add( + new Language( + GuidGenerator.Create(), + cacheItem.CultureName, + cacheItem.UiCultureName, + cacheItem.DisplayName, + cacheItem.TwoLetterISOLanguageName)); + } + else + { + var isUpdated = false; + if (existsLanguage.DisplayName != cacheItem.DisplayName) + { + isUpdated = true; + existsLanguage.SetDisplayName(cacheItem.DisplayName); + } + if (existsLanguage.TwoLetterISOLanguageName != cacheItem.TwoLetterISOLanguageName) + { + isUpdated = true; + existsLanguage.SetTwoLetterISOLanguageName(cacheItem.TwoLetterISOLanguageName); + } + if (isUpdated) + { + updateLanguages.Add(existsLanguage); + } + } + } + + if (newLanguages.Count > 0) + { + Logger.LogInformation("Saved {0} new languages.", newLanguages.Count); + await LanguageRepository.InsertManyAsync(newLanguages, autoSave: true); + } + + if (updateLanguages.Count > 0) + { + Logger.LogInformation("Update {0} changed languages.", updateLanguages.Count); + await LanguageRepository.UpdateManyAsync(updateLanguages, autoSave: true); + } + } + + private async Task RefreshLanguagesCacheAsync() + { + var languages = await LanguageRepository.GetListAsync(); + + var languageCacheItem = new LocalizationLanguageCacheItem( + languages.Select(x => + new LanguageInfo(x.CultureName, x.UiCultureName, x.DisplayName)) + .ToList()); + + await LanguageCache.SetAsync(LocalizationLanguageCacheItem.CacheKey, languageCacheItem); + } + + private async Task SaveResourcesAsync(DynamicResourceInitializerCacheItem[] cacheItems) + { + var newResources = new List(); + var updateResources = new List(); + var existsResources = await ResourceRepository.GetListAsync(); + + foreach (var cacheItem in cacheItems) + { + var existsResource = existsResources.FirstOrDefault(x => x.Name == cacheItem.ResourceName); + if (existsResource == null) + { + newResources.Add( + new Resource( + GuidGenerator.Create(), + cacheItem.ResourceName, + cacheItem.ResourceName, + cacheItem.ResourceName, + cacheItem.DefaultCultureName)); + } + else if (existsResource.DefaultCultureName != cacheItem.DefaultCultureName) + { + existsResource.SetDefaultCultureName(cacheItem.DefaultCultureName); + updateResources.Add(existsResource); + } + } + + if (newResources.Count > 0) + { + Logger.LogInformation("Saved {0} new resources.", newResources.Count); + await ResourceRepository.InsertManyAsync(newResources, autoSave: true); + } + + if (updateResources.Count > 0) + { + Logger.LogInformation("Update {0} changed resources.", updateResources.Count); + await ResourceRepository.UpdateManyAsync(updateResources, autoSave: true); + } + } + + private async Task RefreshResourcesCacheAsync() + { + var resources = await ResourceRepository.GetListAsync(); + + var allResourceCacheItems = new List(); + var allResourceCacheItemDics = new Dictionary(); + foreach (var resource in resources) + { + var resourceCacheItem = new LocalizationResourceCacheItem(resource.Name, resource.DefaultCultureName) + { + IsEnabled = resource.Enable + }; + allResourceCacheItems.Add(resourceCacheItem); + allResourceCacheItemDics[resource.Name] = resourceCacheItem; + } + + await ResourcesCache.SetAsync( + LocalizationResourcesCacheItem.CacheKey, + new LocalizationResourcesCacheItem(allResourceCacheItems)); + + await ResourceCache.SetManyAsync(allResourceCacheItemDics); + } + + private async Task SaveTextsAsync(DynamicTextInitializerCacheItem[] cacheItems) + { + var newTexts = new List(); + var updateTexts = new List(); + + foreach (var cacheItem in cacheItems) + { + var existsTexts = await TextRepository.GetListAsync( + cacheItem.ResourceName, + cacheItem.CultureName); + + foreach (var text in cacheItem.Texts) + { + var existsText = existsTexts.FirstOrDefault(x => x.Key == text.Key); + if (existsText == null) + { + newTexts.Add( + new Text( + cacheItem.ResourceName, + cacheItem.CultureName, + text.Key, + text.Value)); + } + else if (existsText.Value != text.Value) + { + existsText.SetValue(text.Value); + updateTexts.Add(existsText); + } + } + } + + if (newTexts.Count > 0) + { + Logger.LogInformation("Saved {0} new texts.", newTexts.Count); + await TextRepository.InsertManyAsync(newTexts, autoSave: true); + } + + if (updateTexts.Count > 0) + { + Logger.LogInformation("Update {0} changed texts.", updateTexts.Count); + await TextRepository.UpdateManyAsync(updateTexts, autoSave: true); + } + } + + private async Task RefreshTextsCacheAsync(DynamicTextInitializerCacheItem[] cacheItems) + { + foreach (var cacheItem in cacheItems) + { + var setTexts = new Dictionary(); + var allTexts = await TextRepository.GetListAsync(cacheItem.ResourceName, cacheItem.CultureName); + foreach (var text in allTexts) + { + setTexts[text.Key] = text.Value; + } + + var textCacheKey = LocalizationTextCacheItem.CalculateCacheKey(cacheItem.ResourceName, cacheItem.CultureName); + var textCacheItem = new LocalizationTextCacheItem(cacheItem.ResourceName, cacheItem.CultureName, setTexts); + + await LocalizationTextCache.SetAsync(textCacheKey, textCacheItem); + } + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs index c6fd8ef3d..3cc690608 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs @@ -1,10 +1,8 @@ using Microsoft.Extensions.Options; -using System; using System.Linq; using System.Threading.Tasks; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; -using Volo.Abp.DistributedLocking; using Volo.Abp.Localization; namespace LINGYUN.Abp.LocalizationManagement.External; @@ -14,32 +12,20 @@ public class ExternalLocalizationStoreCache : IExternalLocalizationStoreCache, I protected IDistributedCache ResourceCache { get; } protected IDistributedCache ResourcesCache { get; } protected AbpLocalizationOptions LocalizationOptions { get; } - protected IResourceRepository ResourceRepository { get; } - protected IAbpDistributedLock DistributedLock { get; } public ExternalLocalizationStoreCache( IDistributedCache resourcesCache, IDistributedCache resourceCache, - IOptions localizationOptions, - IResourceRepository resourceRepository, - IAbpDistributedLock distributedLock) + IOptions localizationOptions) { ResourceCache = resourceCache; ResourcesCache = resourcesCache; - ResourceRepository = resourceRepository; - DistributedLock = distributedLock; LocalizationOptions = localizationOptions.Value; } - public async virtual Task RemoveAsync(string resourceName) - { - await ResourceCache.RemoveAsync(resourceName); - await ResourcesCache.RemoveAsync(LocalizationResourcesCacheItem.CacheKey); - } - public async virtual Task GetResourceNamesAsync() { - var cacheItem = await GetResourcesCacheItemAsync(); + var cacheItem = await ResourcesCache.GetAsync(LocalizationResourcesCacheItem.CacheKey); return cacheItem.Resources .Where(x => x.IsEnabled) @@ -57,108 +43,18 @@ public class ExternalLocalizationStoreCache : IExternalLocalizationStoreCache, I public async virtual Task GetResourceOrNullAsync(string resourceName) { - var cacheItem = await GetResourceCacheItemAsync(resourceName); + var cacheItem = await ResourceCache.GetAsync(resourceName); return cacheItem?.IsEnabled == true ? cacheItem : null; } public async virtual Task GetResourcesAsync() { - var cacheItem = await GetResourcesCacheItemAsync(); + var cacheItem = await ResourcesCache.GetAsync(LocalizationResourcesCacheItem.CacheKey); return cacheItem?.Resources .Where(x => x.IsEnabled) .Where(x => !LocalizationOptions.Resources.ContainsKey(x.Name)) .ToArray(); } - - internal async Task UpdateCache(string resourceName) - { - if (resourceName.IsNullOrWhiteSpace()) - { - await CreateResourcesCacheItemAsync(); - } - else - { - await CreateResourceCacheItemAsync(resourceName); - } - } - - protected async virtual Task GetResourceCacheItemAsync(string resourceName) - { - var cacheItem = await ResourceCache.GetAsync(resourceName); - if (cacheItem != null) - { - return cacheItem; - } - - return await CreateResourceCacheItemAsync(resourceName); - } - - protected async virtual Task CreateResourceCacheItemAsync(string resourceName) - { - await using var handle = await DistributedLock.TryAcquireAsync($"{nameof(ExternalLocalizationStoreCache)}_{nameof(CreateResourceCacheItemAsync)}"); - - if (handle == null) - { - return null; - } - - LocalizationResourceCacheItem cacheItem; - var resource = await ResourceRepository.FindByNameAsync(resourceName); - if (resource == null) - { - cacheItem = new LocalizationResourceCacheItem(resourceName) - { - IsEnabled = false - }; - } - else - { - cacheItem = new LocalizationResourceCacheItem(resource.Name, resource.DefaultCultureName) - { - IsEnabled = resource.Enable - }; - } - - await ResourceCache.SetAsync(resourceName, cacheItem); - - return cacheItem; - } - - protected async virtual Task GetResourcesCacheItemAsync() - { - var cacheItem = await ResourcesCache.GetAsync(LocalizationResourcesCacheItem.CacheKey); - if (cacheItem != null) - { - return cacheItem; - } - - return await CreateResourcesCacheItemAsync(); - } - - protected async virtual Task CreateResourcesCacheItemAsync() - { - await using var handle = await DistributedLock.TryAcquireAsync($"{nameof(ExternalLocalizationStoreCache)}_{nameof(CreateResourcesCacheItemAsync)}"); - - if (handle == null) - { - return null; - } - - var resources = await ResourceRepository.GetListAsync(); - var resourceItems = resources - .Where(x => !LocalizationOptions.Resources.ContainsKey(x.Name)) - .Select(x => new LocalizationResourceCacheItem(x.Name, x.DefaultCultureName) - { - IsEnabled = x.Enable, - }) - .ToList(); - - var cacheItem = new LocalizationResourcesCacheItem(resourceItems); - - await ResourcesCache.SetAsync(LocalizationResourcesCacheItem.CacheKey, cacheItem); - - return cacheItem; - } } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs index e5f796c73..37a72f62a 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs @@ -1,11 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; -using Volo.Abp.DistributedLocking; using Volo.Abp.Localization; using Volo.Abp.Threading; @@ -14,43 +12,19 @@ namespace LINGYUN.Abp.LocalizationManagement.External; public class ExternalLocalizationTextStoreCache : IExternalLocalizationTextStoreCache, ISingletonDependency { protected ConcurrentDictionary MemoryCache { get; } - - protected IAbpDistributedLock DistributedLock { get; } - protected IServiceScopeFactory ServiceScopeFactory { get; } protected IDistributedCache DistributedCache { get; } protected IDistributedCache StampCache { get; } public ExternalLocalizationTextStoreCache( - IAbpDistributedLock distributedLock, - IServiceScopeFactory serviceScopeFactory, IDistributedCache distributedCache, IDistributedCache stampCache) { - DistributedLock = distributedLock; - ServiceScopeFactory = serviceScopeFactory; DistributedCache = distributedCache; StampCache = stampCache; MemoryCache = new ConcurrentDictionary(); } - public async virtual Task RemoveAsync(string resourceName, string cultureName) - { - var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resourceName, cultureName); - var stampCacheKey = ExternalLocalizationTextStampCacheItem.CalculateCacheKey(resourceName, cultureName); - - await using var lockHandle = await DistributedLock.TryAcquireAsync(cacheKey); - - if (lockHandle == null) - { - return; - } - - await DistributedCache.RemoveAsync(cacheKey); - - await StampCache.SetAsync(stampCacheKey, new ExternalLocalizationTextStampCacheItem(Guid.NewGuid().ToString())); - } - public Dictionary GetTexts(LocalizationResourceBase resource, string cultureName) { var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); @@ -97,7 +71,7 @@ public class ExternalLocalizationTextStoreCache : IExternalLocalizationTextStore return distributeCacheItem.Texts; } - distributeCacheItem = await CreateCacheItemAsync(resource, cultureName); + distributeCacheItem = await GetAndRefreshMemoryCacheItemAsync(resource.ResourceName, cultureName); if (distributeCacheItem == null) { @@ -114,41 +88,30 @@ public class ExternalLocalizationTextStoreCache : IExternalLocalizationTextStore internal async Task UpdateCache(LocalizationResourceBase resource, string cultureName) { - await CreateCacheItemAsync(resource, cultureName); + await GetAndRefreshMemoryCacheItemAsync(resource.ResourceName, cultureName); } - protected async virtual Task CreateCacheItemAsync(LocalizationResourceBase resource, string cultureName) + internal async Task UpdateCache(string resourceName, string cultureName) { - await using var lockHandle = await DistributedLock.TryAcquireAsync($"{nameof(ExternalLocalizationTextStoreCache)}_{nameof(CreateCacheItemAsync)}"); + await GetAndRefreshMemoryCacheItemAsync(resourceName, cultureName); + } - if (lockHandle == null) + protected async virtual Task GetAndRefreshMemoryCacheItemAsync(string resourceName, string cultureName) + { + var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resourceName, cultureName); + var cacheItem = await DistributedCache.GetAsync(cacheKey); + if (cacheItem != null) { - return null; - } - - var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); - var stampCacheKey = ExternalLocalizationTextStampCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); + var stampCacheKey = ExternalLocalizationTextStampCacheItem.CalculateCacheKey(resourceName, cultureName); - using var scope = ServiceScopeFactory.CreateScope(); - var repo = scope.ServiceProvider.GetRequiredService(); + var stampCacheItem = new ExternalLocalizationTextStampCacheItem(Guid.NewGuid().ToString()); + await StampCache.SetAsync(stampCacheKey, stampCacheItem); - var texts = await repo.GetListAsync(resource.ResourceName, cultureName); + MemoryCache[cacheKey] = new LocalizationTextMemoryCacheItem(cacheItem.Texts, stampCacheItem.Stamp); - var fillTexts = new Dictionary(); - - foreach (var text in texts) - { - fillTexts[text.Key] = text.Value; + return cacheItem; } - var cacheItem = new ExternalLocalizationTextCacheItem(fillTexts); - await DistributedCache.SetAsync(cacheKey, cacheItem); - - var stampCacheItem = new ExternalLocalizationTextStampCacheItem(Guid.NewGuid().ToString()); - await StampCache.SetAsync(stampCacheKey, stampCacheItem); - - MemoryCache[cacheKey] = new LocalizationTextMemoryCacheItem(cacheItem.Texts, stampCacheItem.Stamp); - - return cacheItem; + return null; } } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs index cc3825d69..37622b100 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs @@ -11,6 +11,4 @@ public interface IExternalLocalizationStoreCache Task GetResourceNamesAsync(); Task GetResourcesAsync(); - - Task RemoveAsync(string resourceName); } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs index 3ad00d885..7c1c918e6 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs @@ -9,6 +9,4 @@ public interface IExternalLocalizationTextStoreCache Dictionary GetTexts(LocalizationResourceBase resource, string cultureName); Task> GetTextsAsync(LocalizationResourceBase resource, string cultureName); - - Task RemoveAsync(string resourceName, string cultureName); } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs deleted file mode 100644 index cb8cbe422..000000000 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events; -using Volo.Abp.EventBus; - -namespace LINGYUN.Abp.LocalizationManagement.External; - -public class LocalizationResourceCacheInvalidator : - ILocalEventHandler>, - ITransientDependency -{ - private readonly IExternalLocalizationTextStoreCache _externalLocalizationTextStoreCache; - private readonly ILocalizationLanguageStoreCache _localizationLanguageStoreCache; - private readonly IExternalLocalizationStoreCache _externalLocalizationStoreCache; - public LocalizationResourceCacheInvalidator( - IExternalLocalizationTextStoreCache externalLocalizationTextStoreCache, - ILocalizationLanguageStoreCache localizationLanguageStoreCache, - IExternalLocalizationStoreCache externalLocalizationStoreCache) - { - _externalLocalizationTextStoreCache = externalLocalizationTextStoreCache; - _localizationLanguageStoreCache = localizationLanguageStoreCache; - _externalLocalizationStoreCache = externalLocalizationStoreCache; - } - - public async virtual Task HandleEventAsync(EntityChangedEventData eventData) - { - await _externalLocalizationStoreCache.RemoveAsync(eventData.Entity.Name); -; - var languages = await _localizationLanguageStoreCache.GetLanguagesAsync(); - - foreach (var language in languages) - { - await _externalLocalizationTextStoreCache.RemoveAsync(eventData.Entity.Name, language.CultureName); - } - } -} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs index 1bd160c3a..db983834a 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs @@ -18,6 +18,11 @@ public class LocalizationResourceCacheItem public bool IsEnabled { get; set; } + public LocalizationResourceCacheItem() + { + + } + public LocalizationResourceCacheItem( string name, string defaultCulture = null, diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs index 29a82b9dc..feb27fc82 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -16,4 +17,6 @@ public interface IResourceRepository : IRepository Task FindByNameAsync( string name, CancellationToken cancellationToken = default); + + Task> GetActivedListAsync(CancellationToken cancellationToken = default); } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheInvalidator.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheInvalidator.cs deleted file mode 100644 index 70ae35136..000000000 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheInvalidator.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Threading.Tasks; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events; -using Volo.Abp.EventBus; - -namespace LINGYUN.Abp.LocalizationManagement; - -public class LocalizationLanguageCacheInvalidator: ILocalEventHandler>, ITransientDependency -{ - private readonly IDistributedCache _localizationLanguageCache; - public LocalizationLanguageCacheInvalidator(IDistributedCache localizationLanguageCache) - { - _localizationLanguageCache = localizationLanguageCache; - } - - public async virtual Task HandleEventAsync(EntityChangedEventData eventData) - { - await _localizationLanguageCache.RemoveAsync(LocalizationLanguageCacheItem.CacheKey); - } -} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageStoreCache.cs index 62427f03e..769782084 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageStoreCache.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageStoreCache.cs @@ -1,12 +1,9 @@ using Microsoft.Extensions.Options; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading.Tasks; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; -using Volo.Abp.DistributedLocking; -using Volo.Abp.Domain.ChangeTracking; using Volo.Abp.Localization; namespace LINGYUN.Abp.LocalizationManagement; @@ -14,64 +11,20 @@ namespace LINGYUN.Abp.LocalizationManagement; public class LocalizationLanguageStoreCache : ILocalizationLanguageStoreCache, ITransientDependency { protected IDistributedCache LanguageCache { get; } - protected ILanguageRepository LanguageRepository { get; } - protected IAbpDistributedLock DistributedLock { get; } protected AbpLocalizationOptions Options { get; } public LocalizationLanguageStoreCache( - IDistributedCache languageCache, - ILanguageRepository languageRepository, - IAbpDistributedLock distributedLock, + IDistributedCache languageCache, IOptions options) { LanguageCache = languageCache; - LanguageRepository = languageRepository; - DistributedLock = distributedLock; Options = options.Value; } - [DisableEntityChangeTracking] public async virtual Task> GetLanguagesAsync() - { - var cacheItem = await GetCacheItemAsync(); - - return cacheItem?.Languages.ToImmutableList() ?? [..Options.Languages]; - } - - internal async Task UpdateCache() - { - await CreateCacheItemAsync(); - } - - protected async virtual Task GetCacheItemAsync() { var cacheItem = await LanguageCache.GetAsync(LocalizationLanguageCacheItem.CacheKey); - if (cacheItem != null) - { - return cacheItem; - } - return await CreateCacheItemAsync(); - } - - protected async virtual Task CreateCacheItemAsync() - { - await using var handle = await DistributedLock.TryAcquireAsync($"{nameof(LocalizationLanguageStoreCache)}_{nameof(GetCacheItemAsync)}"); - - if (handle == null) - { - return null; - } - - var languages = await LanguageRepository.GetListAsync(); - - var cacheItem = new LocalizationLanguageCacheItem( - languages.Select(x => - new LanguageInfo(x.CultureName, x.UiCultureName, x.DisplayName)) - .ToList()); - - await LanguageCache.SetAsync(LocalizationLanguageCacheItem.CacheKey, cacheItem); - - return cacheItem; + return cacheItem?.Languages.ToImmutableList() ?? [..Options.Languages]; } } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs deleted file mode 100644 index 5d845e4f8..000000000 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs +++ /dev/null @@ -1,32 +0,0 @@ -using LINGYUN.Abp.LocalizationManagement.External; -using System.Threading.Tasks; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events; -using Volo.Abp.EventBus; - -namespace LINGYUN.Abp.LocalizationManagement; - -public class LocalizationTextCacheInvalidator : ILocalEventHandler>, ITransientDependency -{ - private readonly IDistributedCache _localizationTextCache; - private readonly IExternalLocalizationTextStoreCache _externalLocalizationTextStoreCache; - public LocalizationTextCacheInvalidator( - IDistributedCache localizationTextCache, - IExternalLocalizationTextStoreCache externalLocalizationTextStoreCache) - { - _externalLocalizationTextStoreCache = externalLocalizationTextStoreCache; - _localizationTextCache = localizationTextCache; - } - - public async virtual Task HandleEventAsync(EntityChangedEventData eventData) - { - var cacheKey = LocalizationTextCacheItem.CalculateCacheKey( - eventData.Entity.ResourceName, - eventData.Entity.CultureName); - - await _localizationTextCache.RemoveAsync(cacheKey); - - await _externalLocalizationTextStoreCache.RemoveAsync(eventData.Entity.ResourceName, eventData.Entity.CultureName); - } -} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextStoreCache.cs index 9fb076a36..9dd0414a4 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextStoreCache.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextStoreCache.cs @@ -1,12 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Localization; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; -using Volo.Abp.DistributedLocking; -using Volo.Abp.Domain.Repositories; using Volo.Abp.Localization; using Volo.Abp.Threading; @@ -16,17 +13,10 @@ public class LocalizationTextStoreCache : ILocalizationTextStoreCache, ISingleto { private static readonly SemaphoreSlim _cacheLock = new SemaphoreSlim(1, 1); private static readonly LocalizationResourceDictionary _staticCache = new LocalizationResourceDictionary(); - - protected IAbpDistributedLock DistributedLock { get; } - protected IServiceScopeFactory ServiceScopeFactory { get; } protected IDistributedCache LocalizationTextCache { get; } public LocalizationTextStoreCache( - IAbpDistributedLock distributedLock, - IServiceScopeFactory serviceScopeFactory, IDistributedCache localizationTextCache) { - DistributedLock = distributedLock; - ServiceScopeFactory = serviceScopeFactory; LocalizationTextCache = localizationTextCache; } @@ -44,7 +34,7 @@ public class LocalizationTextStoreCache : ILocalizationTextStoreCache, ISingleto public async virtual Task FillAsync(LocalizationResourceBase resource, string cultureName, Dictionary dictionary) { - var cacheItem = await GetCacheItemAsync(resource, cultureName); + var cacheItem = await GetCacheItemAsync(resource.ResourceName, cultureName); if (cacheItem != null) { foreach (var text in cacheItem.Texts) @@ -66,14 +56,19 @@ public class LocalizationTextStoreCache : ILocalizationTextStoreCache, ISingleto } internal async Task UpdateCache(LocalizationResourceBase resource, string cultureName) + { + await UpdateCache(resource.ResourceName, cultureName); + } + + internal async Task UpdateCache(string resourceName, string cultureName) { using (await _cacheLock.LockAsync()) { - var cacheItem = await GetCacheItemAsync(resource, cultureName); + var cacheItem = await GetCacheItemAsync(resourceName, cultureName); if (cacheItem != null) { var textDic = _staticCache - .GetOrAdd(resource.ResourceName, _ => new LocalizationCultureDictionary()) + .GetOrAdd(resourceName, _ => new LocalizationCultureDictionary()) .GetOrAdd(cultureName, _ => new LocalizationTextDictionary()); foreach (var text in cacheItem.Texts) @@ -84,41 +79,9 @@ public class LocalizationTextStoreCache : ILocalizationTextStoreCache, ISingleto } } - protected async virtual Task GetCacheItemAsync(LocalizationResourceBase resource, string cultureName) + protected async virtual Task GetCacheItemAsync(string resourceName, string cultureName) { - // 异步本地化函数不受影响 - var cacheKey = LocalizationTextCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); - var cacheItem = await LocalizationTextCache.GetAsync(cacheKey); - if (cacheItem != null) - { - return cacheItem; - } - - await using var handle = await DistributedLock.TryAcquireAsync($"{nameof(LocalizationTextStoreCache)}_{nameof(GetCacheItemAsync)}"); - - if (handle == null) - { - return null; - } - - var setTexts = new Dictionary(); - using (var scope = ServiceScopeFactory.CreateScope()) - { - var repo = scope.ServiceProvider.GetRequiredService(); - var texts = await repo.GetListAsync(resource.ResourceName, cultureName); - using (repo.DisableTracking()) - { - foreach (var text in texts) - { - setTexts[text.Key] = text.Value; - } - } - } - - cacheItem = new LocalizationTextCacheItem(resource.ResourceName, cultureName, setTexts); - - await LocalizationTextCache.SetAsync(cacheKey, cacheItem); - - return cacheItem; + var cacheKey = LocalizationTextCacheItem.CalculateCacheKey(resourceName, cultureName); + return await LocalizationTextCache.GetAsync(cacheKey); } } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs index 2172b1a77..b08ac4410 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs @@ -1,87 +1,46 @@ -using LINGYUN.Abp.LocalizationManagement.External; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Text.Json; using System.Threading.Tasks; -using Volo.Abp; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; -using Volo.Abp.DistributedLocking; -using Volo.Abp.Guids; +using Volo.Abp.EventBus.Distributed; using Volo.Abp.Localization; -using Volo.Abp.Threading; -using Volo.Abp.Uow; namespace LINGYUN.Abp.LocalizationManagement; public class StaticLocalizationSaver : IStaticLocalizationSaver, ITransientDependency { protected ILogger Logger { get; } - - protected IDistributedCache Cache { get; } - protected IGuidGenerator GuidGenerator { get; } - protected IAbpDistributedLock DistributedLock { get; } - protected IUnitOfWorkManager UnitOfWorkManager { get; } - protected AbpDistributedCacheOptions CacheOptions { get; } - protected IApplicationInfoAccessor ApplicationInfoAccessor { get; } - protected ICancellationTokenProvider CancellationTokenProvider { get; } + protected IDistributedEventBus DistributedEventBus { get; } protected IStringLocalizerFactory StringLocalizerFactory { get; } protected AbpLocalizationOptions LocalizationOptions { get; } protected AbpLocalizationManagementOptions LocalizationManagementOptions { get; } - - protected IExternalLocalizationTextStoreCache ExternalLocalizationTextStoreCache { get; } - protected IExternalLocalizationStoreCache ExternalLocalizationStoreCache { get; } - protected ILocalizationLanguageStoreCache LocalizationLanguageStoreCache { get; } - protected ILocalizationTextStoreCache LocalizationTextStoreCache { get; } - - protected ILanguageRepository LanguageRepository { get; } - protected IResourceRepository ResourceRepository { get; } - protected ITextRepository TextRepository { get; } + protected IDistributedCache DynamicLanguageCache { get; } + protected IDistributedCache DynamicResourceCache { get; } + protected IDistributedCache DynamicTextCache { get; } public StaticLocalizationSaver( ILogger logger, - IDistributedCache cache, - IGuidGenerator guidGenerator, - IAbpDistributedLock distributedLock, - IUnitOfWorkManager unitOfWorkManager, - IApplicationInfoAccessor applicationInfoAccessor, - ICancellationTokenProvider cancellationTokenProvider, - IStringLocalizerFactory stringLocalizerFactory, - IOptions cacheOptions, - IOptions localizationOptions, - IOptions localizationManagementOptions, - IExternalLocalizationTextStoreCache externalLocalizationTextStoreCache, - IExternalLocalizationStoreCache externalLocalizationStoreCache, - ILocalizationLanguageStoreCache localizationLanguageStoreCache, - ILocalizationTextStoreCache localizationTextStoreCache, - ILanguageRepository languageRepository, - IResourceRepository resourceRepository, - ITextRepository textRepository) + IDistributedEventBus distributedEventBus, + IStringLocalizerFactory stringLocalizerFactory, + IOptions localizationOptions, + IOptions localizationManagementOptions, + IDistributedCache dynamicLanguageCache, + IDistributedCache dynamicResourceCache, + IDistributedCache dynamicTextCache) { Logger = logger; - Cache = cache; - GuidGenerator = guidGenerator; - DistributedLock = distributedLock; - UnitOfWorkManager = unitOfWorkManager; - CacheOptions = cacheOptions.Value; - ApplicationInfoAccessor = applicationInfoAccessor; - CancellationTokenProvider = cancellationTokenProvider; + DistributedEventBus = distributedEventBus; StringLocalizerFactory = stringLocalizerFactory; LocalizationOptions = localizationOptions.Value; LocalizationManagementOptions = localizationManagementOptions.Value; - ExternalLocalizationTextStoreCache = externalLocalizationTextStoreCache; - ExternalLocalizationStoreCache = externalLocalizationStoreCache; - LocalizationLanguageStoreCache = localizationLanguageStoreCache; - LocalizationTextStoreCache = localizationTextStoreCache; - LanguageRepository = languageRepository; - ResourceRepository = resourceRepository; - TextRepository = textRepository; + DynamicLanguageCache = dynamicLanguageCache; + DynamicResourceCache = dynamicResourceCache; + DynamicTextCache = dynamicTextCache; } public async virtual Task SaveAsync() @@ -91,265 +50,72 @@ public class StaticLocalizationSaver : IStaticLocalizationSaver, ITransientDepen return; } - Logger.LogDebug("Waiting to acquire the distributed lock for saving static localizations..."); - - await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( - GetApplicationDistributedLockKey(), - TimeSpan.FromSeconds(5)); - if (applicationLockHandle == null) - { - return; - } - - using var unitOfWork = UnitOfWorkManager.Begin(true, true); - try - { - await SaveLanguagesAsync(); - await SaveResourcesAsync(); - await SaveTextsAsync(); - - await PreCacheDynamicLocalizationsAsync(); - } - catch (Exception ex) - { - Logger.LogInformation("Filed to save static localizations."); - Logger.LogWarning(ex.ToString()); - try - { - await unitOfWork.RollbackAsync(); - } - catch - { - Logger.LogInformation("Filed to rollback saving static localizations."); - } - throw; - } - - await unitOfWork.CompleteAsync(); - Logger.LogInformation("Completed to save static localizations."); - } + var languageCacheItems = new Dictionary(); + var resourceCacheItems = new Dictionary(); + var textCacheItems = new Dictionary(); - private async Task PreCacheDynamicLocalizationsAsync() - { - if (LocalizationLanguageStoreCache is LocalizationLanguageStoreCache languageStoreCache) - { - await languageStoreCache.UpdateCache(); - } - - foreach (var resource in LocalizationOptions.Resources) + var localizationResources = LocalizationOptions.Resources.Values.OfType().ToArray(); + foreach (var language in LocalizationOptions.Languages) { - if (ExternalLocalizationStoreCache is ExternalLocalizationStoreCache localizationStoreCache) - { - await localizationStoreCache.UpdateCache(resource.Key); - } - - foreach (var language in LocalizationOptions.Languages) + if (!languageCacheItems.Any(x => x.Value.CultureName == language.CultureName)) { - if (ExternalLocalizationTextStoreCache is ExternalLocalizationTextStoreCache externalLocalizationTextStoreCache) - { - await externalLocalizationTextStoreCache.UpdateCache(resource.Value, language.CultureName); - } - if (LocalizationTextStoreCache is LocalizationTextStoreCache localizationTextStoreCache) - { - await localizationTextStoreCache.UpdateCache(resource.Value, language.CultureName); - } + languageCacheItems.Add( + Guid.NewGuid().ToString(), + new DynamicLanguageInitializerCacheItem( + language.CultureName, + language.UiCultureName, + language.DisplayName, + language.TwoLetterISOLanguageName)); } - } - } - private async Task SaveLanguagesAsync() - { - var languageHashKey = GetApplicationLanguageHashKey(); - var languageHashCache = await Cache.GetStringAsync(languageHashKey, CancellationTokenProvider.Token); - var languageHash = CalculateLanguagesHash(LocalizationOptions.Languages); - if (languageHashCache != languageHash) - { - var newLanguages = new List(); - foreach (var language in LocalizationOptions.Languages) + foreach (var resource in localizationResources) { - if (await LanguageRepository.FindByCultureNameAsync(language.CultureName, cancellationToken: CancellationTokenProvider.Token) == null) + if (!resourceCacheItems.Any(x => x.Value.ResourceName == resource.ResourceName)) { - newLanguages.Add( - new Language( - GuidGenerator.Create(), - language.CultureName, - language.UiCultureName, - language.DisplayName, - language.TwoLetterISOLanguageName)); + resourceCacheItems.Add( + Guid.NewGuid().ToString(), + new DynamicResourceInitializerCacheItem( + resource.ResourceName, + resource.DefaultCultureName)); } - } - if (newLanguages.Any()) - { - Logger.LogInformation("Saved {0} new languages.", newLanguages.Count); - - await LanguageRepository.InsertManyAsync(newLanguages, cancellationToken: CancellationTokenProvider.Token); - } - - await Cache.SetStringAsync(languageHashKey, languageHash, CancellationTokenProvider.Token); - } - } - - private async Task SaveResourcesAsync() - { - var resourceHashKey = GetApplicationResourceHashKey(); - var resourceHashCache = await Cache.GetStringAsync(resourceHashKey, CancellationTokenProvider.Token); - var resourceHash = CalculateResourceHash(LocalizationOptions.Resources.Select(x => x.Value).ToList()); - if (resourceHashCache != resourceHash) - { - var newResources = new List(); - foreach (var resource in LocalizationOptions.Resources) - { - if (await ResourceRepository.FindByNameAsync(resource.Key, cancellationToken: CancellationTokenProvider.Token) == null) - { - newResources.Add( - new Resource( - GuidGenerator.Create(), - resource.Value.ResourceName, - resource.Value.ResourceName, - resource.Value.ResourceName, - resource.Value.DefaultCultureName)); - } - } - if (newResources.Any()) - { - Logger.LogInformation("Saved {0} new resources.", newResources.Count); - - await ResourceRepository.InsertManyAsync(newResources, cancellationToken: CancellationTokenProvider.Token); - } - - await Cache.SetStringAsync(resourceHashKey, resourceHash, CancellationTokenProvider.Token); - } - } - - private async Task SaveTextsAsync() - { - var createTexts = new List(); - var updateTexts = new List(); - - var localizationResources = LocalizationOptions.Resources.Values.OfType().ToArray(); - - var languageResourceTexts = new Dictionary>>(); - - foreach (var language in LocalizationOptions.Languages) - { - var resourceTexts = new Dictionary>(); - foreach (var resource in localizationResources) - { using (CultureHelper.Use(language.CultureName, language.UiCultureName)) { var stringLocalizer = StringLocalizerFactory.Create(resource.ResourceType); var localizedStrings = stringLocalizer.GetAllStrings(false, false, false); - var textHashKey = GetApplicationTextHashKey(resource.ResourceName, language.CultureName); - var textHashCache = await Cache.GetStringAsync(textHashKey, CancellationTokenProvider.Token); - var textHash = CalculateTextsHash(localizedStrings); - if (textHashCache == textHash) + if (!localizedStrings.Any()) { continue; } - - var savedLocalizedStrings = await TextRepository.GetListAsync( - resource.ResourceName, - language.CultureName); + var localizedStringsDic = new Dictionary(); foreach (var localizedString in localizedStrings) { - var findLocalizedString = savedLocalizedStrings.FirstOrDefault(x => x.Key == localizedString.Name); - if (findLocalizedString == null) - { - createTexts.Add( - new Text( - resource.ResourceName, - language.CultureName, - localizedString.Name, - localizedString.Value)); - continue; - } - - if (!string.Equals(findLocalizedString.Value, localizedString.Value, StringComparison.InvariantCultureIgnoreCase)) - { - findLocalizedString.SetValue(localizedString.Value); - updateTexts.Add(findLocalizedString); - } + localizedStringsDic.TryAdd(localizedString.Name, localizedString.Value); } - await Cache.SetStringAsync(textHashKey, textHash, CancellationTokenProvider.Token); + textCacheItems.Add( + Guid.NewGuid().ToString(), + new DynamicTextInitializerCacheItem( + resource.ResourceName, + language.CultureName, + localizedStringsDic)); } } - - languageResourceTexts[language.CultureName] = resourceTexts; } - if (createTexts.Any()) - { - Logger.LogInformation("Saved {0} new texts.", createTexts.Count); - - await TextRepository.InsertManyAsync(createTexts, cancellationToken: CancellationTokenProvider.Token); - } - if (updateTexts.Any()) - { - Logger.LogInformation("Update {0} changed texts.", updateTexts.Count); - - await TextRepository.UpdateManyAsync(updateTexts, cancellationToken: CancellationTokenProvider.Token); - } - } - - private string GetApplicationDistributedLockKey() - { - return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_AbpLocalizationsUpdateLock"; - } - - private string GetApplicationResourceHashKey() - { - return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_AbpLocalizationResourcesHash"; - } - - private string GetApplicationLanguageHashKey() - { - return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_AbpLocalizationLanguagesHash"; - } - private string GetApplicationTextHashKey(string resourceName, string cultureName) - { - return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_{resourceName}_{cultureName}_AbpLocalizationTextsHash"; - } - - private static string CalculateResourceHash(List localizationResources) - { - var stringBuilder = new StringBuilder(); - - stringBuilder.Append("LocalizationResources:"); - stringBuilder.AppendLine(JsonSerializer.Serialize(localizationResources)); - - return stringBuilder - .ToString() - .ToMd5(); - } - - private static string CalculateLanguagesHash(List languageInfos) - { - var stringBuilder = new StringBuilder(); - - stringBuilder.Append("LocalizationLanguages:"); - stringBuilder.AppendLine(JsonSerializer.Serialize(languageInfos)); - - return stringBuilder - .ToString() - .ToMd5(); - } - - private static string CalculateTextsHash(IEnumerable localizers) - { - var stringBuilder = new StringBuilder(); - - stringBuilder.Append("LocalizationTexts:"); - stringBuilder.AppendLine(JsonSerializer.Serialize( - localizers.Select(x => new NameValue(x.Name, x.Value)).ToList())); + await DynamicLanguageCache.SetManyAsync(languageCacheItems); + await DynamicResourceCache.SetManyAsync(resourceCacheItems); + await DynamicTextCache.SetManyAsync(textCacheItems); - return stringBuilder - .ToString() - .ToMd5(); + await DistributedEventBus.PublishAsync( + new DynamicLanguageInitializerEto(languageCacheItems.Keys.ToArray())); + await DistributedEventBus.PublishAsync( + new DynamicResourceInitializerEto(resourceCacheItems.Keys.ToArray())); + await DistributedEventBus.PublishAsync( + new DynamicTextInitializerEto(textCacheItems.Keys.ToArray())); } } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore/LINGYUN/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore/LINGYUN/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs index 269e308fe..e34aeddcc 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore/LINGYUN/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore/LINGYUN/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -40,4 +41,10 @@ public class EfCoreResourceRepository : EfCoreRepository x.Name.Equals(name)) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); } + + public async virtual Task> GetActivedListAsync(CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).Where(x => x.Enable) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } From d86bd587e006783b83c69a5a26b3b5637806e7c8 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 17:04:33 +0800 Subject: [PATCH 35/40] feat: Optimize dynamic templates --- .../TextTemplateDefinitionAppService.cs | 49 +++++-------------- .../ITextTemplateDefinitionSerializer.cs | 12 ----- 2 files changed, 12 insertions(+), 49 deletions(-) delete mode 100644 aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Domain/LINGYUN/Abp/TextTemplating/ITextTemplateDefinitionSerializer.cs diff --git a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Application/LINGYUN/Abp/TextTemplating/TextTemplateDefinitionAppService.cs b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Application/LINGYUN/Abp/TextTemplating/TextTemplateDefinitionAppService.cs index f8a03c757..b941162c1 100644 --- a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Application/LINGYUN/Abp/TextTemplating/TextTemplateDefinitionAppService.cs +++ b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Application/LINGYUN/Abp/TextTemplating/TextTemplateDefinitionAppService.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Authorization; using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading.Tasks; @@ -17,38 +16,22 @@ namespace LINGYUN.Abp.TextTemplating; public class TextTemplateDefinitionAppService : AbpTextTemplatingAppServiceBase, ITextTemplateDefinitionAppService { private readonly ITemplateDefinitionStore _store; - private readonly ITemplateDefinitionManager _templateDefinitionManager; - private readonly IStaticTemplateDefinitionStore _staticTemplateDefinitionStore; - private readonly IDynamicTemplateDefinitionStore _dynamicTemplateDefinitionStore; private readonly ITextTemplateDefinitionRepository _repository; private readonly ILocalizableStringSerializer _localizableStringSerializer; public TextTemplateDefinitionAppService( ITemplateDefinitionStore store, ITextTemplateDefinitionRepository repository, - ITemplateDefinitionManager templateDefinitionManager, - ILocalizableStringSerializer localizableStringSerializer, - IStaticTemplateDefinitionStore staticTemplateDefinitionStore, - IDynamicTemplateDefinitionStore dynamicTemplateDefinitionStore) + ILocalizableStringSerializer localizableStringSerializer) { _store = store; _repository = repository; - _templateDefinitionManager = templateDefinitionManager; _localizableStringSerializer = localizableStringSerializer; - _staticTemplateDefinitionStore = staticTemplateDefinitionStore; - _dynamicTemplateDefinitionStore = dynamicTemplateDefinitionStore; } [Authorize(AbpTextTemplatingPermissions.TextTemplateDefinition.Create)] public async virtual Task CreateAsync(TextTemplateDefinitionCreateDto input) { - var template = await _templateDefinitionManager.GetOrNullAsync(input.Name); - if (template != null) - { - throw new BusinessException(AbpTextTemplatingErrorCodes.TextTemplateDefinition.NameAlreadyExists) - .WithData(nameof(TextTemplateDefinition.Name), input.Name); - } - var templateDefinitionRecord = await _repository.FindByNameAsync(input.Name); if (templateDefinitionRecord != null) { @@ -82,28 +65,20 @@ public class TextTemplateDefinitionAppService : AbpTextTemplatingAppServiceBase, public async virtual Task GetByNameAsync(string name) { - var templateDefinition = await _staticTemplateDefinitionStore.GetOrNullAsync(name); - if (templateDefinition != null) + var templateDefinitionRecord = await _repository.FindByNameAsync(name); + if (templateDefinitionRecord == null) { - return DefinitionToDto(templateDefinition, true); + return null; } - templateDefinition = await _dynamicTemplateDefinitionStore.GetOrNullAsync(name); - return DefinitionToDto(templateDefinition); + return DefinitionRecordToDto(templateDefinitionRecord); } public async virtual Task> GetListAsync(TextTemplateDefinitionGetListInput input) { var templateDtoList = new List(); - var staticTemplates = await _staticTemplateDefinitionStore.GetAllAsync(); - var staticTemplateNames = staticTemplates - .Select(p => p.Name) - .ToImmutableHashSet(); - templateDtoList.AddRange(staticTemplates.Select(d => DefinitionToDto(d, true))); - var dynamicTemplates = await _dynamicTemplateDefinitionStore.GetAllAsync(); - templateDtoList.AddRange(dynamicTemplates - .Where(d => !staticTemplateNames.Contains(d.Name)) - .Select(d => DefinitionToDto(d))); + var dynamicTemplates = await _repository.GetListAsync(includeDetails: false); + templateDtoList.AddRange(dynamicTemplates.Select(DefinitionRecordToDto)); return new ListResultDto(templateDtoList .WhereIf(input.IsStatic.HasValue, x => x.IsStatic == input.IsStatic) @@ -115,11 +90,6 @@ public class TextTemplateDefinitionAppService : AbpTextTemplatingAppServiceBase, [Authorize(AbpTextTemplatingPermissions.TextTemplateDefinition.Update)] public async virtual Task UpdateAsync(string name, TextTemplateDefinitionUpdateDto input) { - if (await _staticTemplateDefinitionStore.GetOrNullAsync(name) != null) - { - throw new BusinessException(AbpTextTemplatingErrorCodes.TextTemplateDefinition.StaticTemplateNotAllowedChanged) - .WithData("Name", name); - } var templateDefinitionRecord = await _repository.FindByNameAsync(name); if (templateDefinitionRecord == null) @@ -141,6 +111,11 @@ public class TextTemplateDefinitionAppService : AbpTextTemplatingAppServiceBase, } else { + if (templateDefinitionRecord.IsStatic) + { + throw new BusinessException(AbpTextTemplatingErrorCodes.TextTemplateDefinition.StaticTemplateNotAllowedChanged) + .WithData("Name", name); + } UpdateByInput(templateDefinitionRecord, input); await _store.UpdateAsync(templateDefinitionRecord); diff --git a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Domain/LINGYUN/Abp/TextTemplating/ITextTemplateDefinitionSerializer.cs b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Domain/LINGYUN/Abp/TextTemplating/ITextTemplateDefinitionSerializer.cs deleted file mode 100644 index e00909333..000000000 --- a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Domain/LINGYUN/Abp/TextTemplating/ITextTemplateDefinitionSerializer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JetBrains.Annotations; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Volo.Abp.TextTemplating; - -namespace LINGYUN.Abp.TextTemplating; -public interface ITextTemplateDefinitionSerializer -{ - Task SerializeAsync(TemplateDefinition template); -} From 3580ec806ac19e06b8479cdea2f5b52181a82420 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 17 Jun 2026 17:16:32 +0800 Subject: [PATCH 36/40] feat: Optimize the query for retrieving all tenant caches --- .../Distributed/NotificationEventHandler.cs | 13 ++-- .../Distributed/TenantSynchronizer.cs | 70 ------------------- .../MultiTenancy/ITenantConfigurationCache.cs | 12 ---- .../MultiTenancy/TenantConfigurationCache.cs | 62 ---------------- .../TenantConfigurationCacheItem.cs | 20 ------ .../BlobTempCleanupBackgroundWorker.cs | 9 ++- .../MultiTenancy/ITenantConfigurationCache.cs | 8 --- .../MultiTenancy/TenantConfigurationCache.cs | 47 ------------- .../TenantConfigurationCacheItem.cs | 19 ----- .../Tenants/TenantCacheItemInvalidator.cs | 21 ++++-- .../LINGYUN/Abp/Saas/Tenants/TenantStore.cs | 33 ++++++--- .../Abp/Saas/Tenants/TenantsCacheItem.cs | 28 ++++++++ .../Distributed/NotificationEventHandler.cs | 20 ++---- .../Distributed/TenantEventHandler.cs | 46 ------------ .../MultiTenancy/ITenantConfigurationCache.cs | 10 --- .../MultiTenancy/TenantConfigurationCache.cs | 59 ---------------- .../TenantConfigurationCacheItem.cs | 19 ----- .../appsettings.json | 3 +- .../BlobTempCleanupBackgroundWorker.cs | 10 +-- .../MultiTenancy/ITenantConfigurationCache.cs | 10 --- .../MultiTenancy/TenantConfigurationCache.cs | 50 ------------- .../TenantConfigurationCacheItem.cs | 20 ------ .../Distributed/NotificationEventHandler.cs | 13 ++-- .../Distributed/TenantSynchronizer.cs | 70 ------------------- .../MultiTenancy/ITenantConfigurationCache.cs | 12 ---- .../MultiTenancy/TenantConfigurationCache.cs | 62 ---------------- .../TenantConfigurationCacheItem.cs | 20 ------ 27 files changed, 96 insertions(+), 670 deletions(-) delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/TenantSynchronizer.cs delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/ITenantConfigurationCache.cs delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCache.cs delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCacheItem.cs delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/ITenantConfigurationCache.cs delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCache.cs delete mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCacheItem.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantsCacheItem.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/TenantEventHandler.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/ITenantConfigurationCache.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCache.cs delete mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCacheItem.cs delete mode 100644 aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs delete mode 100644 aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs delete mode 100644 aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs delete mode 100644 aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/TenantSynchronizer.cs delete mode 100644 aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs delete mode 100644 aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs delete mode 100644 aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs index 8ba419705..29c23b3dc 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs @@ -1,5 +1,4 @@ using LINGYUN.Abp.MicroService.MessageService.BackgroundJobs; -using LINGYUN.Abp.MicroService.MessageService.MultiTenancy; using LINGYUN.Abp.Notifications; using LINGYUN.Abp.Notifications.Templating; using Microsoft.Extensions.Localization; @@ -57,9 +56,9 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed /// protected ICurrentTenant CurrentTenant { get; } /// - /// Reference to . + /// Reference to . /// - protected ITenantConfigurationCache TenantConfigurationCache { get; } + protected ITenantStore TenantStore { get; } /// /// Reference to . /// @@ -108,7 +107,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed IClock clock, ICurrentTenant currentTenant, ISettingProvider settingProvider, - ITenantConfigurationCache tenantConfigurationCache, + ITenantStore tenantStore, IJsonSerializer jsonSerializer, ITemplateRenderer templateRenderer, IBackgroundJobManager backgroundJobManager, @@ -123,7 +122,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed { Clock = clock; Options = options.Value; - TenantConfigurationCache = tenantConfigurationCache; + TenantStore = tenantStore; CurrentTenant = currentTenant; SettingProvider = settingProvider; JsonSerializer = jsonSerializer; @@ -165,7 +164,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed { await SendToTenantAsync(null, notification, eventData, result); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { @@ -202,7 +201,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed { await SendToTenantAsync(null, notification, eventData); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/TenantSynchronizer.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/TenantSynchronizer.cs deleted file mode 100644 index bfa3281be..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/TenantSynchronizer.cs +++ /dev/null @@ -1,70 +0,0 @@ -using LINGYUN.Abp.Data.DbMigrator; -using LINGYUN.Abp.MicroService.MessageService.MultiTenancy; -using LINGYUN.Abp.Notifications; -using LINGYUN.Abp.Saas.Tenants; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events.Distributed; -using Volo.Abp.EventBus.Distributed; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; - -namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed -{ - public class TenantSynchronizer : - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler, - ITransientDependency - { - protected ILogger Logger { get; } - protected ICurrentTenant CurrentTenant { get; } - protected IUnitOfWorkManager UnitOfWorkManager { get; } - protected IDbSchemaMigrator DbSchemaMigrator { get; } - protected INotificationSender NotificationSender { get; } - protected ITenantConfigurationCache TenantConfigurationCache { get; } - protected INotificationSubscriptionManager NotificationSubscriptionManager { get; } - - public TenantSynchronizer( - ICurrentTenant currentTenant, - IDbSchemaMigrator dbSchemaMigrator, - IUnitOfWorkManager unitOfWorkManager, - INotificationSender notificationSender, - ITenantConfigurationCache tenantConfigurationCache, - INotificationSubscriptionManager notificationSubscriptionManager, - ILogger logger) - { - Logger = logger; - - CurrentTenant = currentTenant; - DbSchemaMigrator = dbSchemaMigrator; - UnitOfWorkManager = unitOfWorkManager; - TenantConfigurationCache = tenantConfigurationCache; - - NotificationSender = notificationSender; - NotificationSubscriptionManager = notificationSubscriptionManager; - } - - public async virtual Task HandleEventAsync(EntityCreatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(EntityUpdatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(EntityDeletedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(TenantConnectionStringUpdatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - } -} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/ITenantConfigurationCache.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/ITenantConfigurationCache.cs deleted file mode 100644 index f9f8d02a3..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/ITenantConfigurationCache.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MicroService.MessageService.MultiTenancy; - -public interface ITenantConfigurationCache -{ - Task RefreshAsync(); - - Task> GetTenantsAsync(); -} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCache.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCache.cs deleted file mode 100644 index ab9e4ec67..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCache.cs +++ /dev/null @@ -1,62 +0,0 @@ -using LINGYUN.Abp.Saas.Tenants; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MicroService.MessageService.MultiTenancy; - -public class TenantConfigurationCache : ITenantConfigurationCache, ITransientDependency -{ - protected ITenantRepository TenantRepository { get; } - protected IDistributedCache TenantCache { get; } - - public TenantConfigurationCache( - ITenantRepository tenantRepository, - IDistributedCache tenantCache) - { - TenantRepository = tenantRepository; - TenantCache = tenantCache; - } - - public async virtual Task RefreshAsync() - { - var cacheKey = GetCacheKey(); - - await TenantCache.RemoveAsync(cacheKey); - } - - public async virtual Task> GetTenantsAsync() - { - return (await GetForCacheItemAsync()).Tenants; - } - - protected async virtual Task GetForCacheItemAsync() - { - var cacheKey = GetCacheKey(); - var cacheItem = await TenantCache.GetAsync(cacheKey); - if (cacheItem == null) - { - var allActiveTenants = await TenantRepository.GetListAsync(); - - cacheItem = new TenantConfigurationCacheItem( - allActiveTenants - .Where(t => t.IsActive) - .Select(t => new TenantConfiguration(t.Id, t.Name) - { - IsActive = t.IsActive, - }).ToList()); - - await TenantCache.SetAsync(cacheKey, cacheItem); - } - - return cacheItem; - } - - protected virtual string GetCacheKey() - { - return "_Abp_Tenant_Configuration"; - } -} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCacheItem.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCacheItem.cs deleted file mode 100644 index 8504783cb..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/MultiTenancy/TenantConfigurationCacheItem.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MicroService.MessageService.MultiTenancy; - -[IgnoreMultiTenancy] -public class TenantConfigurationCacheItem -{ - public List Tenants { get; set; } - - public TenantConfigurationCacheItem() - { - Tenants = new List(); - } - - public TenantConfigurationCacheItem(List tenants) - { - Tenants = tenants; - } -} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs index 33625a332..ced3b33f4 100644 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs @@ -1,5 +1,4 @@ using LINGYUN.Abp.BlobManagement; -using LINGYUN.Abp.MicroService.PlatformService.MultiTenancy; using Microsoft.Extensions.Options; using Volo.Abp.BackgroundWorkers; using Volo.Abp.DistributedLocking; @@ -12,7 +11,7 @@ public class BlobTempCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase { protected ICurrentTenant CurrentTenant { get; } protected IAbpDistributedLock DistributedLock { get; } - protected ITenantConfigurationCache TenantConfigurationCache { get; } + protected ITenantStore TenantStore { get; } public BlobTempCleanupBackgroundWorker( AbpAsyncTimer timer, @@ -20,12 +19,12 @@ public class BlobTempCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase IOptionsMonitor cleanupOptions, IAbpDistributedLock distributedLock, ICurrentTenant currentTenant, - ITenantConfigurationCache tenantConfigurationCache) + ITenantStore tenantStore) : base(timer, serviceScopeFactory) { CurrentTenant = currentTenant; DistributedLock = distributedLock; - TenantConfigurationCache = tenantConfigurationCache; + TenantStore = tenantStore; timer.Period = cleanupOptions.CurrentValue.CleanupPeriod; } @@ -41,7 +40,7 @@ public class BlobTempCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase { await ExecuteCleanService(workerContext); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/ITenantConfigurationCache.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/ITenantConfigurationCache.cs deleted file mode 100644 index 1b6c5cf69..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/ITenantConfigurationCache.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MicroService.PlatformService.MultiTenancy; - -public interface ITenantConfigurationCache -{ - Task> GetTenantsAsync(); -} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCache.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCache.cs deleted file mode 100644 index bd881db3d..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCache.cs +++ /dev/null @@ -1,47 +0,0 @@ -using LINGYUN.Abp.Saas.Tenants; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MicroService.PlatformService.MultiTenancy; - -public class TenantConfigurationCache : ITenantConfigurationCache, ITransientDependency -{ - protected ITenantRepository TenantRepository { get; } - protected IDistributedCache TenantCache { get; } - - public TenantConfigurationCache( - ITenantRepository tenantRepository, - IDistributedCache tenantCache) - { - TenantRepository = tenantRepository; - TenantCache = tenantCache; - } - - public async virtual Task> GetTenantsAsync() - { - return (await GetForCacheItemAsync()).Tenants; - } - - protected async virtual Task GetForCacheItemAsync() - { - var cacheKey = "_Abp_Tenant_Configuration"; - var cacheItem = await TenantCache.GetAsync(cacheKey); - if (cacheItem == null) - { - var allActiveTenants = await TenantRepository.GetListAsync(); - - cacheItem = new TenantConfigurationCacheItem( - allActiveTenants - .Where(t => t.IsActive) - .Select(t => new TenantConfiguration(t.Id, t.Name) - { - IsActive = t.IsActive, - }).ToList()); - - await TenantCache.SetAsync(cacheKey, cacheItem); - } - - return cacheItem; - } -} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCacheItem.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCacheItem.cs deleted file mode 100644 index 8bd0abd3d..000000000 --- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.PlatformService/MultiTenancy/TenantConfigurationCacheItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MicroService.PlatformService.MultiTenancy; - -[IgnoreMultiTenancy] -public class TenantConfigurationCacheItem -{ - public List Tenants { get; set; } - - public TenantConfigurationCacheItem() - { - Tenants = new List(); - } - - public TenantConfigurationCacheItem(List tenants) - { - Tenants = tenants; - } -} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs index e18b7e4ae..aa5a3d167 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs @@ -17,11 +17,15 @@ public class TenantCacheItemInvalidator : ILocalEventHandler>, ITransientDependency { - protected IDistributedCache Cache { get; } + protected IDistributedCache TenantCache { get; } + protected IDistributedCache TenantsCache { get; } - public TenantCacheItemInvalidator(IDistributedCache cache) + public TenantCacheItemInvalidator( + IDistributedCache tenantCache, + IDistributedCache tenantsCache) { - Cache = cache; + TenantCache = tenantCache; + TenantsCache = tenantsCache; } public async virtual Task HandleEventAsync(EntityCreatedEto eto) @@ -46,7 +50,7 @@ public class TenantCacheItemInvalidator : protected async virtual Task RemoveTenantCache(Guid tenantId, string tenantName = null) { - var keys = new string[] + var removeTenantKeys = new string[] { TenantCacheItem.CalculateCacheKey(null, tenantName), TenantCacheItem.CalculateCacheKey(tenantId, null), @@ -55,6 +59,13 @@ public class TenantCacheItemInvalidator : // 同时移除租户版本缓存 EditionCacheItem.CalculateCacheKey(tenantId) }; - await Cache.RemoveManyAsync(keys, considerUow: true); + await TenantCache.RemoveManyAsync(removeTenantKeys, considerUow: true); + + var removeTenantsKeys = new string[] + { + TenantsCacheItem.CalculateCacheKey(true), + TenantsCacheItem.CalculateCacheKey(false) + }; + await TenantsCache.RemoveManyAsync(removeTenantsKeys, considerUow: true); } } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantStore.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantStore.cs index fcc2ff27e..fe254027e 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantStore.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantStore.cs @@ -1,7 +1,7 @@ -using System; +using JetBrains.Annotations; +using System; using System.Collections.Generic; using System.Threading.Tasks; -using JetBrains.Annotations; using Volo.Abp; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; @@ -15,18 +15,21 @@ public class TenantStore : ITenantStore, ITransientDependency protected ITenantRepository TenantRepository { get; } protected IObjectMapper ObjectMapper { get; } protected ICurrentTenant CurrentTenant { get; } - protected IDistributedCache Cache { get; } + protected IDistributedCache TenantCache { get; } + protected IDistributedCache TenantsCache { get; } public TenantStore( ITenantRepository tenantRepository, IObjectMapper objectMapper, ICurrentTenant currentTenant, - IDistributedCache cache) + IDistributedCache tenantCache, + IDistributedCache tenantsCache) { TenantRepository = tenantRepository; ObjectMapper = objectMapper; CurrentTenant = currentTenant; - Cache = cache; + TenantCache = tenantCache; + TenantsCache = tenantsCache; } public async virtual Task FindAsync(string name) @@ -41,8 +44,16 @@ public class TenantStore : ITenantStore, ITransientDependency public async virtual Task> GetListAsync(bool includeDetails = false) { - return ObjectMapper.Map, List>( - await TenantRepository.GetListAsync(includeDetails)); + var cacheKey = TenantsCacheItem.CalculateCacheKey(includeDetails); + var cacheItem = await TenantsCache.GetAsync(cacheKey); + if (cacheItem == null) + { + var tenants = await TenantRepository.GetListAsync(includeDetails); + var tenantConfiurations = ObjectMapper.Map, List>(tenants); + cacheItem = new TenantsCacheItem(tenantConfiurations); + await TenantsCache.SetAsync(cacheKey, cacheItem, considerUow: true); + } + return [.. cacheItem.Tenants]; } [Obsolete("Use FindAsync method.")] @@ -61,7 +72,7 @@ public class TenantStore : ITenantStore, ITransientDependency { var cacheKey = CalculateCacheKey(id, name); - var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true); + var cacheItem = await TenantCache.GetAsync(cacheKey, considerUow: true); if (cacheItem != null) { return cacheItem; @@ -92,7 +103,7 @@ public class TenantStore : ITenantStore, ITransientDependency { var tenantConfiguration = tenant != null ? ObjectMapper.Map(tenant) : null; var cacheItem = new TenantCacheItem(tenantConfiguration); - await Cache.SetAsync(cacheKey, cacheItem, considerUow: true); + await TenantCache.SetAsync(cacheKey, cacheItem, considerUow: true); return cacheItem; } @@ -101,7 +112,7 @@ public class TenantStore : ITenantStore, ITransientDependency { var cacheKey = CalculateCacheKey(id, name); - var cacheItem = Cache.Get(cacheKey, considerUow: true); + var cacheItem = TenantCache.Get(cacheKey, considerUow: true); if (cacheItem != null) { return cacheItem; @@ -133,7 +144,7 @@ public class TenantStore : ITenantStore, ITransientDependency { var tenantConfiguration = tenant != null ? ObjectMapper.Map(tenant) : null; var cacheItem = new TenantCacheItem(tenantConfiguration); - Cache.Set(cacheKey, cacheItem, considerUow: true); + TenantCache.Set(cacheKey, cacheItem, considerUow: true); return cacheItem; } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantsCacheItem.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantsCacheItem.cs new file mode 100644 index 000000000..de4308691 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantsCacheItem.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.Saas.Tenants; + +[Serializable] +[IgnoreMultiTenancy] +[CacheName("AbpSaasTenantsAll")] +public class TenantsCacheItem +{ + private const string CacheKeyFormat = "id:{0}"; + + public List Tenants { get; set; } + public TenantsCacheItem() + { + + } + public TenantsCacheItem(List tenants) + { + Tenants = tenants; + } + public static string CalculateCacheKey(bool includeDetails = false) + { + return string.Format(CacheKeyFormat, includeDetails.ToString()); + } +} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs index 9e163e427..804aba971 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs @@ -1,7 +1,4 @@ -using LINGYUN.Abp.Notifications; -using LINGYUN.Abp.Notifications.Templating; -using LY.MicroService.Applications.Single.BackgroundJobs; -using LY.MicroService.Applications.Single.MultiTenancy; +using LY.MicroService.Applications.Single.BackgroundJobs; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; @@ -9,9 +6,6 @@ using System.Globalization; using Volo.Abp.BackgroundJobs; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; -using Volo.Abp.Json; -using Volo.Abp.Localization; -using Volo.Abp.MultiTenancy; using Volo.Abp.TextTemplating; using Volo.Abp.Timing; using Volo.Abp.Uow; @@ -47,9 +41,9 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed /// protected ICurrentTenant CurrentTenant { get; } /// - /// Reference to . + /// Reference to . /// - protected ITenantConfigurationCache TenantConfigurationCache { get; } + protected ITenantStore TenantStore { get; } /// /// Reference to . /// @@ -97,7 +91,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed public NotificationEventHandler( IClock clock, ICurrentTenant currentTenant, - ITenantConfigurationCache tenantConfigurationCache, + ITenantStore tenantStore, IJsonSerializer jsonSerializer, ITemplateRenderer templateRenderer, IBackgroundJobManager backgroundJobManager, @@ -112,7 +106,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed { Clock = clock; Options = options.Value; - TenantConfigurationCache = tenantConfigurationCache; + TenantStore = tenantStore; CurrentTenant = currentTenant; JsonSerializer = jsonSerializer; TemplateRenderer = templateRenderer; @@ -152,7 +146,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed { await SendToTenantAsync(null, notification, eventData, result); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { @@ -182,7 +176,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed { await SendToTenantAsync(null, notification, eventData); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/TenantEventHandler.cs b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/TenantEventHandler.cs deleted file mode 100644 index 325a36bd0..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/TenantEventHandler.cs +++ /dev/null @@ -1,46 +0,0 @@ -using LINGYUN.Abp.Saas.Tenants; -using LY.MicroService.Applications.Single.MultiTenancy; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events.Distributed; -using Volo.Abp.EventBus.Distributed; -using Volo.Abp.Uow; - -namespace LY.MicroService.Applications.Single.EventBus.Distributed -{ - public class TenantEventHandler : - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler, - ITransientDependency - { - protected ITenantConfigurationCache TenantConfigurationCache { get; } - - public TenantEventHandler( - ITenantConfigurationCache tenantConfigurationCache) - { - TenantConfigurationCache = tenantConfigurationCache; - } - - [UnitOfWork] - public async virtual Task HandleEventAsync(EntityCreatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(EntityUpdatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(EntityDeletedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(TenantConnectionStringUpdatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - } -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/ITenantConfigurationCache.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/ITenantConfigurationCache.cs deleted file mode 100644 index fce53a23b..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/ITenantConfigurationCache.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.Applications.Single.MultiTenancy; - -public interface ITenantConfigurationCache -{ - Task RefreshAsync(); - - Task> GetTenantsAsync(); -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCache.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCache.cs deleted file mode 100644 index bf5c7f017..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCache.cs +++ /dev/null @@ -1,59 +0,0 @@ -using LINGYUN.Abp.Saas.Tenants; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.Applications.Single.MultiTenancy; - -public class TenantConfigurationCache : ITenantConfigurationCache, ITransientDependency -{ - protected ITenantRepository TenantRepository { get; } - protected IDistributedCache TenantCache { get; } - - public TenantConfigurationCache( - ITenantRepository tenantRepository, - IDistributedCache tenantCache) - { - TenantRepository = tenantRepository; - TenantCache = tenantCache; - } - - public async virtual Task RefreshAsync() - { - var cacheKey = GetCacheKey(); - - await TenantCache.RemoveAsync(cacheKey); - } - - public async virtual Task> GetTenantsAsync() - { - return (await GetForCacheItemAsync()).Tenants; - } - - protected async virtual Task GetForCacheItemAsync() - { - var cacheKey = GetCacheKey(); - var cacheItem = await TenantCache.GetAsync(cacheKey); - if (cacheItem == null) - { - var allActiveTenants = await TenantRepository.GetListAsync(); - - cacheItem = new TenantConfigurationCacheItem( - allActiveTenants - .Where(t => t.IsActive) - .Select(t => new TenantConfiguration(t.Id, t.Name) - { - IsActive = t.IsActive, - }).ToList()); - - await TenantCache.SetAsync(cacheKey, cacheItem); - } - - return cacheItem; - } - - protected virtual string GetCacheKey() - { - return "_Abp_Tenant_Configuration"; - } -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCacheItem.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCacheItem.cs deleted file mode 100644 index cc7a2674a..000000000 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MultiTenancy/TenantConfigurationCacheItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.Applications.Single.MultiTenancy; - -[IgnoreMultiTenancy] -public class TenantConfigurationCacheItem -{ - public List Tenants { get; set; } - - public TenantConfigurationCacheItem() - { - Tenants = new List(); - } - - public TenantConfigurationCacheItem(List tenants) - { - Tenants = tenants; - } -} diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.json b/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.json index 85418946b..f17c7dd52 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.json +++ b/aspnet-core/services/LY.MicroService.Applications.Single/appsettings.json @@ -36,7 +36,8 @@ "Override": { "System": "Warning", "Microsoft": "Warning", - "DotNetCore": "Information" + "DotNetCore": "Information", + "LINGYUN.Abp.BlobManagement": "Debug" } }, "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ], diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs index ae121100d..d7b279ac0 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/BackgroundWorkers/BlobTempCleanupBackgroundWorker.cs @@ -1,8 +1,8 @@ using LINGYUN.Abp.BlobManagement; -using LY.MicroService.PlatformManagement.MultiTenancy; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.BackgroundWorkers; using Volo.Abp.DistributedLocking; @@ -13,9 +13,9 @@ namespace LY.MicroService.PlatformManagement.BackgroundWorkers; public class BlobTempCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase { + protected ITenantStore TenantStore { get; } protected ICurrentTenant CurrentTenant { get; } protected IAbpDistributedLock DistributedLock { get; } - protected ITenantConfigurationCache TenantConfigurationCache { get; } public BlobTempCleanupBackgroundWorker( AbpAsyncTimer timer, @@ -23,12 +23,12 @@ public class BlobTempCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase IOptionsMonitor cleanupOptions, IAbpDistributedLock distributedLock, ICurrentTenant currentTenant, - ITenantConfigurationCache tenantConfigurationCache) + ITenantStore tenantStore) : base(timer, serviceScopeFactory) { + TenantStore = tenantStore; CurrentTenant = currentTenant; DistributedLock = distributedLock; - TenantConfigurationCache = tenantConfigurationCache; timer.Period = cleanupOptions.CurrentValue.CleanupPeriod; } @@ -44,7 +44,7 @@ public class BlobTempCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase { await ExecuteCleanService(workerContext); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs deleted file mode 100644 index 7b6736aa0..000000000 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.PlatformManagement.MultiTenancy; - -public interface ITenantConfigurationCache -{ - Task> GetTenantsAsync(); -} diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs deleted file mode 100644 index 91d1e6fe1..000000000 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs +++ /dev/null @@ -1,50 +0,0 @@ -using LINGYUN.Abp.Saas.Tenants; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.PlatformManagement.MultiTenancy; - -public class TenantConfigurationCache : ITenantConfigurationCache, ITransientDependency -{ - protected ITenantRepository TenantRepository { get; } - protected IDistributedCache TenantCache { get; } - - public TenantConfigurationCache( - ITenantRepository tenantRepository, - IDistributedCache tenantCache) - { - TenantRepository = tenantRepository; - TenantCache = tenantCache; - } - - public async virtual Task> GetTenantsAsync() - { - return (await GetForCacheItemAsync()).Tenants; - } - - protected async virtual Task GetForCacheItemAsync() - { - var cacheKey = "_Abp_Tenant_Configuration"; - var cacheItem = await TenantCache.GetAsync(cacheKey); - if (cacheItem == null) - { - var allActiveTenants = await TenantRepository.GetListAsync(); - - cacheItem = new TenantConfigurationCacheItem( - allActiveTenants - .Where(t => t.IsActive) - .Select(t => new TenantConfiguration(t.Id, t.Name) - { - IsActive = t.IsActive, - }).ToList()); - - await TenantCache.SetAsync(cacheKey, cacheItem); - } - - return cacheItem; - } -} diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs deleted file mode 100644 index 7925c4aa7..000000000 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.PlatformManagement.MultiTenancy; - -[IgnoreMultiTenancy] -public class TenantConfigurationCacheItem -{ - public List Tenants { get; set; } - - public TenantConfigurationCacheItem() - { - Tenants = new List(); - } - - public TenantConfigurationCacheItem(List tenants) - { - Tenants = tenants; - } -} diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs index 7805f9ec3..8253b7b31 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs @@ -1,7 +1,6 @@ using LINGYUN.Abp.Notifications; using LINGYUN.Abp.Notifications.Templating; using LY.MicroService.RealtimeMessage.BackgroundJobs; -using LY.MicroService.RealtimeMessage.MultiTenancy; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -57,9 +56,9 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed /// protected ICurrentTenant CurrentTenant { get; } /// - /// Reference to . + /// Reference to . /// - protected ITenantConfigurationCache TenantConfigurationCache { get; } + protected ITenantStore TenantStore { get; } /// /// Reference to . /// @@ -108,7 +107,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed IClock clock, ICurrentTenant currentTenant, ISettingProvider settingProvider, - ITenantConfigurationCache tenantConfigurationCache, + ITenantStore tenantStore, IJsonSerializer jsonSerializer, ITemplateRenderer templateRenderer, IBackgroundJobManager backgroundJobManager, @@ -123,7 +122,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed { Clock = clock; Options = options.Value; - TenantConfigurationCache = tenantConfigurationCache; + TenantStore = tenantStore; CurrentTenant = currentTenant; SettingProvider = settingProvider; JsonSerializer = jsonSerializer; @@ -165,7 +164,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed { await SendToTenantAsync(null, notification, eventData, result); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { @@ -202,7 +201,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed { await SendToTenantAsync(null, notification, eventData); - var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); + var allActiveTenants = (await TenantStore.GetListAsync()).Where(x => x.IsActive); foreach (var activeTenant in allActiveTenants) { diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/TenantSynchronizer.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/TenantSynchronizer.cs deleted file mode 100644 index acd86429c..000000000 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/TenantSynchronizer.cs +++ /dev/null @@ -1,70 +0,0 @@ -using LINGYUN.Abp.Data.DbMigrator; -using LINGYUN.Abp.Notifications; -using LINGYUN.Abp.Saas.Tenants; -using LY.MicroService.RealtimeMessage.MultiTenancy; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events.Distributed; -using Volo.Abp.EventBus.Distributed; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; - -namespace LY.MicroService.RealtimeMessage.EventBus.Distributed -{ - public class TenantSynchronizer : - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler, - ITransientDependency - { - protected ILogger Logger { get; } - protected ICurrentTenant CurrentTenant { get; } - protected IUnitOfWorkManager UnitOfWorkManager { get; } - protected IDbSchemaMigrator DbSchemaMigrator { get; } - protected INotificationSender NotificationSender { get; } - protected ITenantConfigurationCache TenantConfigurationCache { get; } - protected INotificationSubscriptionManager NotificationSubscriptionManager { get; } - - public TenantSynchronizer( - ICurrentTenant currentTenant, - IDbSchemaMigrator dbSchemaMigrator, - IUnitOfWorkManager unitOfWorkManager, - INotificationSender notificationSender, - ITenantConfigurationCache tenantConfigurationCache, - INotificationSubscriptionManager notificationSubscriptionManager, - ILogger logger) - { - Logger = logger; - - CurrentTenant = currentTenant; - DbSchemaMigrator = dbSchemaMigrator; - UnitOfWorkManager = unitOfWorkManager; - TenantConfigurationCache = tenantConfigurationCache; - - NotificationSender = notificationSender; - NotificationSubscriptionManager = notificationSubscriptionManager; - } - - public async virtual Task HandleEventAsync(EntityCreatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(EntityUpdatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(EntityDeletedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - - public async virtual Task HandleEventAsync(TenantConnectionStringUpdatedEto eventData) - { - await TenantConfigurationCache.RefreshAsync(); - } - } -} diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs deleted file mode 100644 index 0706cb924..000000000 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/ITenantConfigurationCache.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.RealtimeMessage.MultiTenancy; - -public interface ITenantConfigurationCache -{ - Task RefreshAsync(); - - Task> GetTenantsAsync(); -} diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs deleted file mode 100644 index df197c6ae..000000000 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCache.cs +++ /dev/null @@ -1,62 +0,0 @@ -using LINGYUN.Abp.Saas.Tenants; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.Caching; -using Volo.Abp.DependencyInjection; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.RealtimeMessage.MultiTenancy; - -public class TenantConfigurationCache : ITenantConfigurationCache, ITransientDependency -{ - protected ITenantRepository TenantRepository { get; } - protected IDistributedCache TenantCache { get; } - - public TenantConfigurationCache( - ITenantRepository tenantRepository, - IDistributedCache tenantCache) - { - TenantRepository = tenantRepository; - TenantCache = tenantCache; - } - - public async virtual Task RefreshAsync() - { - var cacheKey = GetCacheKey(); - - await TenantCache.RemoveAsync(cacheKey); - } - - public async virtual Task> GetTenantsAsync() - { - return (await GetForCacheItemAsync()).Tenants; - } - - protected async virtual Task GetForCacheItemAsync() - { - var cacheKey = GetCacheKey(); - var cacheItem = await TenantCache.GetAsync(cacheKey); - if (cacheItem == null) - { - var allActiveTenants = await TenantRepository.GetListAsync(); - - cacheItem = new TenantConfigurationCacheItem( - allActiveTenants - .Where(t => t.IsActive) - .Select(t => new TenantConfiguration(t.Id, t.Name) - { - IsActive = t.IsActive, - }).ToList()); - - await TenantCache.SetAsync(cacheKey, cacheItem); - } - - return cacheItem; - } - - protected virtual string GetCacheKey() - { - return "_Abp_Tenant_Configuration"; - } -} diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs deleted file mode 100644 index 7c2b77e2c..000000000 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/MultiTenancy/TenantConfigurationCacheItem.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using Volo.Abp.MultiTenancy; - -namespace LY.MicroService.RealtimeMessage.MultiTenancy; - -[IgnoreMultiTenancy] -public class TenantConfigurationCacheItem -{ - public List Tenants { get; set; } - - public TenantConfigurationCacheItem() - { - Tenants = new List(); - } - - public TenantConfigurationCacheItem(List tenants) - { - Tenants = tenants; - } -} From 0d04733a1c1a0de244cff1d096e5330a0795cb5d Mon Sep 17 00:00:00 2001 From: colin Date: Thu, 18 Jun 2026 13:06:19 +0800 Subject: [PATCH 37/40] chore: Update abp framework to 10.4.0 --- .changes/Migration 10.2.0 - 10.4.0.md | 76 +++++ Directory.Packages.props | 46 ++-- .../vben5/apps/app-antd/src/layouts/basic.vue | 10 +- .../src/components/settings/SettingForm.vue | 20 +- .../components/job-infos/JobInfoDrawer.vue | 51 +++- .../src/components/job-infos/JobInfoTable.vue | 18 ++ .../@abp/tasks/src/types/job-infos.ts | 10 +- .../components/properties/PropertyTable.vue | 13 +- .../ui/src/components/properties/types.ts | 1 + .../wechat/src/components/bind-user/index.vue | 15 +- .../@abp/wechat/src/constants/features.ts | 2 + aspnet-core/LINGYUN.MicroService.All.slnx | 1 + aspnet-core/LINGYUN.MicroService.Aspire.slnx | 8 + .../AIServiceModule.cs | 2 + .../appsettings.Development.json | 3 +- .../AdminServiceDataSeeder.cs | 3 +- .../appsettings.Development.json | 1 + .../yarp.json | 30 ++ .../AppHost.cs | 19 +- .../DataSeeds/OpenIddictDataSeeder.cs | 8 +- .../appsettings.Development.json | 1 + .../package.json | 8 +- .../appsettings.Development.json | 1 + .../LocalizationServiceModule.Configure.cs | 8 + .../LocalizationServiceModule.cs | 1 + .../appsettings.Development.json | 1 + .../DataSeeds/NotificationDataSeeder.cs | 120 ++++++++ .../MessageServiceDataSeedConsts.cs | 10 + .../MessageServiceDataSeeder.cs | 33 +++ .../MessageServiceDbMigrationEventHandler.cs | 64 +---- .../MessageServiceDbMigrationService.cs | 10 + .../appsettings.Development.json | 1 + ...UN.Abp.MicroService.PlatformService.csproj | 1 + .../PlatformServiceModule.cs | 2 + .../appsettings.Development.json | 1 + .../appsettings.Development.json | 1 + .../WeChatServiceModule.Configure.cs | 4 +- .../appsettings.Development.json | 1 + .../appsettings.Development.json | 1 + .../appsettings.Development.json | 1 + .../EventBus/CAP/CAPDistributedEventBus.cs | 121 ++++++-- .../AbpTelemetryOpenTelemetryModule.cs | 20 +- .../Abp/WeChat/Common/Utils/Cryptography.cs | 12 + .../Abp/WeChat/Common/Utils/WXBizMsgCrypt.cs | 8 +- aspnet-core/migrate-database.bat | 3 +- .../OpenIddictDataSeederContributor.cs | 8 +- .../DataSeeds/OpenIddictDataSeeder.cs | 8 +- ...IdentitySessionUserInactiveSynchronizer.cs | 18 +- .../InactiveUserDeactivationNotifier.tpl | 2 +- .../InactiveUserDeletionNotifier.tpl | 2 +- .../InactiveUserReminderNotifier.tpl | 2 +- ...eVbenAdmin5NavigationDefinitionProvider.cs | 24 ++ .../TaskManagement/BackgroundJobInfoDto.cs | 4 + ...rviceApplicationsSingleModule.Configure.cs | 1 + .../MicroServiceApplicationsSingleModule.cs | 2 + .../SystemGroupSettingDefinitionProvider.cs | 253 +++++++++++++++++ .../appsettings.Development.json | 34 ++- .../SystemGroupSettingDefinitionProvider.cs | 260 ++++++++++++++++++ ...INGYUN.Abp.BlobStoring.Aliyun.Tests.csproj | 2 +- ...LINGYUN.Abp.BlobStoring.Nexus.Tests.csproj | 2 +- .../LINGYUN.Abp.DataProtection.Tests.csproj | 2 +- ...NGYUN.Abp.EntityFrameworkCore.Tests.csproj | 2 +- ...bp.ExceptionHandling.Emailing.Tests.csproj | 2 +- ...eatures.LimitValidation.Redis.Tests.csproj | 2 +- ....Abp.Features.LimitValidation.Tests.csproj | 2 +- .../LINGYUN.Abp.IdGenerator.Tests.csproj | 2 +- .../LINGYUN.Abp.Localization.Xml.Tests.csproj | 2 +- .../LINGYUN.Abp.Location.Baidu.Tests.csproj | 2 +- .../LINGYUN.Abp.Location.Tencent.Tests.csproj | 2 +- ...LINGYUN.Abp.Rules.RulesEngine.Tests.csproj | 2 +- .../LINGYUN.Abp.WeChat.Work.Tests.csproj | 2 +- 71 files changed, 1224 insertions(+), 191 deletions(-) create mode 100644 .changes/Migration 10.2.0 - 10.4.0.md create mode 100644 apps/vben5/packages/@abp/wechat/src/constants/features.ts create mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/DataSeeds/NotificationDataSeeder.cs create mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDataSeedConsts.cs create mode 100644 aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDataSeeder.cs create mode 100644 aspnet-core/services/LY.MicroService.Applications.Single/Settings/SystemGroupSettingDefinitionProvider.cs create mode 100644 aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Settings/SystemGroupSettingDefinitionProvider.cs diff --git a/.changes/Migration 10.2.0 - 10.4.0.md b/.changes/Migration 10.2.0 - 10.4.0.md new file mode 100644 index 000000000..864bde8f2 --- /dev/null +++ b/.changes/Migration 10.2.0 - 10.4.0.md @@ -0,0 +1,76 @@ +# 10.2.0 - 10.4.0 + +## 模块变更 + +1. [身份标识模块] 增加不活跃用户通知/清理作业,实现了三个通知模板(账户保持活跃通知、账户停用通知、账户删除通知) +2. [身份标识模块] 增加不活跃用户实体 `IdentityUserInactive` 需要执行数据库迁移 +3. [身份标识模块] 增加用户登录Url设置定义: `Abp.Identity.Link.UserLoginUri`, 用于在外部系统中关联用户登录页 +4. [身份认证模块] 增加用户登录Url定义: `Abp.Account.UserLogin` +5. [身份认证模块] 增加关联用户登录功能, 可以实现跨租户用户关联, 切换关联用户登录 +6. [设置管理模块] 增加身份标识模块缺少的设置项: 启用防止密码重用、防止密码重用数量 +7. [设置基础模块] 增加设置定义分组、所属设置、优先级、依赖权限、依赖功能、选择项等常用结构扩展 +8. [设置管理模块] 重构设置管理应用服务接口, 通过预设定的设置定义分组、上下级关系等自动构成Dto结构 + +## 依赖项变更 + +| 库名称 | 原版本 | 现版本 | +| -------------------------------------------- | --------- | ------ | +| Microsoft.AspNetCore.* | 10.0.2 | 10.0.7 | +| Microsoft.Bcl.AsyncInterfaces | 10.0.2 | 10.0.7 | +| Microsoft.Data.Sqlite.Core | 10.0.0 | 10.0.7 | +| Microsoft.EntityFrameworkCore.* | 10.0.2 | 10.0.7 | +| Microting.EntityFrameworkCore.MySql | 10.0.3 | 10.0.7 | +| Microsoft.Extensions.* | 10.0.2 | 10.0.7 | +| OpenTelemetry.Extensions.Hosting | 1.14.0 | 1.15.3 | +| OpenTelemetry.Exporter.Console | 1.14.0 | 1.15.3 | +| OpenTelemetry.Exporter.OpenTelemetryProtocol | 1.14.0 | 1.15.3 | +| OpenTelemetry.Exporter.Zipkin | 1.14.0 | 1.15.3 | +| OpenTelemetry.Instrumentation.AspNetCore | 1.14.0 | 1.15.2 | +| OpenTelemetry.Instrumentation.Http | 1.14.0 | 1.15.1 | +| OpenTelemetry.Instrumentation.Quartz | 1.14.0-beta.2 | 1.15.1-beta.1 | +| OpenTelemetry.Instrumentation.Runtime | 1.14.0 | 1.15.1 | +| OpenTelemetry.Instrumentation.SqlClient | 1.14.0-beta.1 | 1.15.2 | +| OpenIddict.Server.DataProtection | 7.2.0 | 7.5.0 | +| OpenIddict.Validation.DataProtection | 7.2.0 | 7.5.0 | +| System.Threading.Channels | 10.0.0 | 10.0.7 | +| Volo.Abp.* | 10.2.0 | 10.4.0 | +| Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite | 5.2.0 | 5.4.0 | + + + +## 数据库迁移 + +| Project Name | Database Provider | Scripts | EF Core Version | +| ------------------------ | ----------------- | ---------------------------------------------- | --------------- | +| aspire/AuthServer | PostgreSQL | 20260530060327_Add-Identity-User-Inactive | 10.0.2 | +| services/Single | MySQL | 20260529063257_Add-Identity-User-Inactive | 10.0.3 | +| services/Single | PostgreSQL | 20260530055941_Add-Identity-User-Inactive | 10.0.2 | +| services/Single | SqlServer | 20260530060009_Add-Identity-User-Inactive | 10.0.2 | +| services/AuthServer | MySQL | 20260530061141_Add-Identity-User-Inactive | 10.0.3 | + + +## 数据库连接字符串 + +| Module Name | ConnectionString Name | Example(MySQL) | +| ----------------------------- | ---------------------------- | ------------------------------------------------------------ | +| Default | Default | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/Identity | AbpIdentity | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/IdentityServer | AbpIdentityServer | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/OpenIddict | AbpOpenIddict | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/TenantManagement | AbpTenantManagement(AbpSaas) | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/FeatureManagement | AbpFeatureManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/SettingManagement | AbpSettingManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| abp/PermissionManagement | AbpPermissionManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/AIManagement | AbpAIManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/BlobManagement | AbpBlobManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/DataProtectionManagement | AbpDataProtectionManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/Gdpr | AbpGdpr | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/Saas | AbpSaas | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/LocalizationManagement | AbpLocalizationManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/TextTemplating | AbpTextTemplating | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/Platform | AppPlatform | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/MessageService | MessageService | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/NotificationService | Notifications | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/TaskManagement | TaskManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/WebhooksManagement | WebhooksManagement | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | +| labp/Elsa | Workflow | Server=127.0.0.1;Database=abp;User Id=root;Password=123456;SslMode=None | diff --git a/Directory.Packages.props b/Directory.Packages.props index 7c7d36b3d..eae775c5f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,17 +3,17 @@ 10.0.0 2.16.1 3.6.0 - 10.2.0 - 10.2.0 - 10.0.2 - 10.0.2 - 10.0.2 + 10.4.0 + 10.4.0 + 10.0.7 + 10.0.7 + 10.0.7 13.1.0 true - + @@ -164,7 +164,7 @@ - + @@ -186,11 +186,11 @@ - + - + @@ -200,7 +200,7 @@ - + @@ -276,16 +276,16 @@ - - - - - - + + + + + + - - - + + + @@ -318,7 +318,7 @@ - + @@ -365,8 +365,8 @@ - - + + @@ -383,7 +383,7 @@ - + diff --git a/apps/vben5/apps/app-antd/src/layouts/basic.vue b/apps/vben5/apps/app-antd/src/layouts/basic.vue index 755598abb..eeb8302f4 100644 --- a/apps/vben5/apps/app-antd/src/layouts/basic.vue +++ b/apps/vben5/apps/app-antd/src/layouts/basic.vue @@ -14,7 +14,7 @@ import { UserDropdown, } from '@vben/layouts'; import { preferences } from '@vben/preferences'; -import { useAccessStore, useUserStore } from '@vben/stores'; +import { useAccessStore, useTabbarStore, useUserStore } from '@vben/stores'; import { useAbpStore } from '@abp/core'; @@ -30,11 +30,12 @@ const notifications = ref([]); useSessions(); -const { replace } = useRouter(); +const router = useRouter(); const abpStore = useAbpStore(); const userStore = useUserStore(); const authStore = useAuthStore(); const accessStore = useAccessStore(); +const tabbarStore = useTabbarStore(); const { destroyWatermark, updateWatermark } = useWatermark(); const showDot = computed(() => notifications.value.some((item) => !item.isRead), @@ -57,7 +58,7 @@ const menus = computed(() => [ }, { handler: () => { - replace('/account/my-settings'); + router.replace('/account/my-settings'); }, icon: UserSettingsIcon, text: $t('abp.account.settings.title'), @@ -109,7 +110,8 @@ async function handleLinkUser(token: string) { async function handleLinkLogin(userId: string, tenantId?: string) { await authStore.linkUseLogin(userId, tenantId, () => { - window.location.reload(); + tabbarStore.closeAllTabs(router); + window.location.replace('/'); }); } watch( diff --git a/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue b/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue index a2dd403ae..0b172671b 100644 --- a/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue +++ b/apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue @@ -41,7 +41,6 @@ const emits = defineEmits<{ const FormItem = Form.Item; const TabPane = Tabs.TabPane; const CollapsePanel = Collapse.Panel; -const SelectOption = Select.Option; const defaultModel: SettingsUpdateInput = { settings: [], @@ -104,6 +103,15 @@ function onValueChange(setting: SettingDetail) { } } +function onFilterOption(input: string, option: any) { + if (option?.value || option?.name) { + return ( + option?.name?.toLowerCase().includes(input.toLowerCase()) || + option?.value?.toLowerCase().includes(input.toLowerCase()) + ); + } +} + onMounted(onGet); @@ -190,16 +198,20 @@ onMounted(onGet); @@ -217,6 +237,7 @@ function onDeleteParam(record: JobParamter) { > @@ -228,6 +249,7 @@ function onDeleteParam(record: JobParamter) { > @@ -241,6 +263,7 @@ function onDeleteParam(record: JobParamter) {