Browse Source

Merge pull request #1506 from colinin/dev

chore: update abp framework to 10.4.0
pull/1507/head
yx lin 3 months ago
committed by GitHub
parent
commit
faa236336e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 76
      .changes/Migration 10.2.0 - 10.4.0.md
  2. 2
      .github/workflows/release.yml
  3. 51
      Directory.Packages.props
  4. 50
      apps/vben5/apps/app-antd/src/layouts/basic.vue
  5. 1
      apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json
  6. 1
      apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json
  7. 40
      apps/vben5/apps/app-antd/src/store/auth.ts
  8. 14
      apps/vben5/apps/app-antd/src/views/_core/authentication/login.vue
  9. 1
      apps/vben5/packages/@abp/account/src/api/index.ts
  10. 54
      apps/vben5/packages/@abp/account/src/api/useLinkUsersApi.ts
  11. 198
      apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue
  12. 1
      apps/vben5/packages/@abp/account/src/components/index.ts
  13. 16
      apps/vben5/packages/@abp/account/src/hooks/useOAuthService.ts
  14. 2
      apps/vben5/packages/@abp/account/src/types/index.ts
  15. 14
      apps/vben5/packages/@abp/account/src/types/link-user.ts
  16. 10
      apps/vben5/packages/@abp/account/src/types/token.ts
  17. 25
      apps/vben5/packages/@abp/account/src/utils/auth.ts
  18. 3
      apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue
  19. 3
      apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionTable.vue
  20. 3
      apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue
  21. 2
      apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue
  22. 3
      apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue
  23. 5
      apps/vben5/packages/@abp/blob-management/package.json
  24. 26
      apps/vben5/packages/@abp/blob-management/src/api/useBlobsApi.ts
  25. 4
      apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal.vue
  26. 106
      apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal1.vue
  27. 9
      apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFileTable.vue
  28. 3
      apps/vben5/packages/@abp/blob-management/src/components/containers/BlobContainerTable.vue
  29. 3
      apps/vben5/packages/@abp/data-protection/src/components/entity-type-infos/EntityTypeInfoTable.vue
  30. 3
      apps/vben5/packages/@abp/demo/src/components/books/BookTable.vue
  31. 2
      apps/vben5/packages/@abp/features/src/components/features/FeatureModal.vue
  32. 3
      apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue
  33. 3
      apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue
  34. 3
      apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitRoleTable.vue
  35. 3
      apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue
  36. 3
      apps/vben5/packages/@abp/identity/src/components/organization-units/SelectMemberModal.vue
  37. 3
      apps/vben5/packages/@abp/identity/src/components/organization-units/SelectRoleModal.vue
  38. 3
      apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue
  39. 3
      apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue
  40. 3
      apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue
  41. 3
      apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue
  42. 3
      apps/vben5/packages/@abp/notifications/src/components/my-notifilers/MyNotificationTable.vue
  43. 3
      apps/vben5/packages/@abp/notifications/src/components/send-records/NotificationSendRecordTable.vue
  44. 3
      apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationTable.vue
  45. 3
      apps/vben5/packages/@abp/openiddict/src/components/authorizations/AuthorizationTable.vue
  46. 3
      apps/vben5/packages/@abp/openiddict/src/components/scopes/ScopeTable.vue
  47. 3
      apps/vben5/packages/@abp/openiddict/src/components/tokens/TokenTable.vue
  48. 3
      apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue
  49. 3
      apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue
  50. 2
      apps/vben5/packages/@abp/permissions/src/components/permissions/PermissionModal.vue
  51. 3
      apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue
  52. 3
      apps/vben5/packages/@abp/platform/src/components/messages/email/EmailMessageTable.vue
  53. 3
      apps/vben5/packages/@abp/platform/src/components/messages/sms/SmsMessageTable.vue
  54. 3
      apps/vben5/packages/@abp/saas/src/components/editions/EditionTable.vue
  55. 3
      apps/vben5/packages/@abp/saas/src/components/tenants/TenantTable.vue
  56. 1
      apps/vben5/packages/@abp/settings/package.json
  57. 2
      apps/vben5/packages/@abp/settings/src/api/useDefinitionsApi.ts
  58. 30
      apps/vben5/packages/@abp/settings/src/api/useSettingsApi.ts
  59. 42
      apps/vben5/packages/@abp/settings/src/components/settings/SettingForm.vue
  60. 21
      apps/vben5/packages/@abp/settings/src/components/settings/SystemSetting.vue
  61. 51
      apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoDrawer.vue
  62. 21
      apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoTable.vue
  63. 10
      apps/vben5/packages/@abp/tasks/src/types/job-infos.ts
  64. 20
      apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue
  65. 1
      apps/vben5/packages/@abp/ui/src/components/properties/types.ts
  66. 3
      apps/vben5/packages/@abp/webhooks/src/components/send-attempts/WebhookSendAttemptTable.vue
  67. 3
      apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue
  68. 15
      apps/vben5/packages/@abp/wechat/src/components/bind-user/index.vue
  69. 2
      apps/vben5/packages/@abp/wechat/src/constants/features.ts
  70. 2
      apps/vben5/pnpm-workspace.yaml
  71. 16
      aspnet-core/LINGYUN.MicroService.All.slnx
  72. 20
      aspnet-core/LINGYUN.MicroService.Aspire.slnx
  73. 7
      aspnet-core/LINGYUN.MicroService.SingleProject.slnx
  74. 2
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs
  75. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/appsettings.Development.json
  76. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService.EntityFrameworkCore/AdminServiceDataSeeder.cs
  77. 2
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/AdminServiceModule.cs
  78. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/LINGYUN.Abp.MicroService.AdminService.csproj
  79. 258
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/SystemGroupSettingDefinitionProvider.cs
  80. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/appsettings.Development.json
  81. 30
      aspnet-core/aspire/LINGYUN.Abp.MicroService.ApiGateway/yarp.json
  82. 19
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AppHost/AppHost.cs
  83. 3
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/AuthServerMigrationsDbContext.cs
  84. 8
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/DataSeeds/OpenIddictDataSeeder.cs
  85. 1403
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.Designer.cs
  86. 48
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.cs
  87. 42
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/AuthServerMigrationsDbContextModelSnapshot.cs
  88. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer/appsettings.Development.json
  89. 8
      aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer/package.json
  90. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.IdentityService/appsettings.Development.json
  91. 8
      aspnet-core/aspire/LINGYUN.Abp.MicroService.LocalizationService/LocalizationServiceModule.Configure.cs
  92. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.LocalizationService/LocalizationServiceModule.cs
  93. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.LocalizationService/appsettings.Development.json
  94. 120
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/DataSeeds/NotificationDataSeeder.cs
  95. 10
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDataSeedConsts.cs
  96. 33
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDataSeeder.cs
  97. 64
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDbMigrationEventHandler.cs
  98. 10
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDbMigrationService.cs
  99. 13
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs
  100. 70
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/TenantSynchronizer.cs

76
.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 |

2
.github/workflows/release.yml

@ -14,4 +14,4 @@ jobs:
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
automatic_release_tag: "10.2.0"
automatic_release_tag: "10.4.0"

51
Directory.Packages.props

@ -3,17 +3,17 @@
<DotNetCoreCAPPackageVersion>10.0.0</DotNetCoreCAPPackageVersion>
<ElsaPackageVersion>2.16.1</ElsaPackageVersion>
<ElsaNextPackageVersion>3.6.0</ElsaNextPackageVersion>
<VoloAbpPackageVersion>10.2.0</VoloAbpPackageVersion>
<LINGYUNAbpPackageVersion>10.2.0</LINGYUNAbpPackageVersion>
<MicrosoftExtensionsPackageVersion>10.0.2</MicrosoftExtensionsPackageVersion>
<MicrosoftAspNetCorePackageVersion>10.0.2</MicrosoftAspNetCorePackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>10.0.2</MicrosoftEntityFrameworkCorePackageVersion>
<VoloAbpPackageVersion>10.4.0</VoloAbpPackageVersion>
<LINGYUNAbpPackageVersion>10.4.0</LINGYUNAbpPackageVersion>
<MicrosoftExtensionsPackageVersion>10.0.7</MicrosoftExtensionsPackageVersion>
<MicrosoftAspNetCorePackageVersion>10.0.7</MicrosoftAspNetCorePackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>10.0.7</MicrosoftEntityFrameworkCorePackageVersion>
<AspirePackageVersion>13.1.0</AspirePackageVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- Abp Framework -->
<ItemGroup>
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="5.2.0" />
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="5.4.0" />
<PackageVersion Include="Volo.Abp.AI" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Core" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Account.Application" Version="$(VoloAbpPackageVersion)" />
@ -164,7 +164,7 @@
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.7" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
@ -186,11 +186,11 @@
<PackageVersion Include="MySql.EntityFrameworkCore" Version="10.0.1" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql.Json.Microsoft" Version="9.0.0" />
<PackageVersion Include="Microting.EntityFrameworkCore.MySql" Version="10.0.3" />
<PackageVersion Include="Microting.EntityFrameworkCore.MySql" Version="10.0.7" />
</ItemGroup>
<!-- Aspire -->
<ItemGroup>
<PackageVersion Include="Aspire.Hosting.Elasticsearch" Version="13.0.0" />
<PackageVersion Include="Aspire.Hosting.Elasticsearch" Version="$(AspirePackageVersion)" />
<PackageVersion Include="Aspire.Hosting.JavaScript" Version="$(AspirePackageVersion)" />
<PackageVersion Include="Aspire.Hosting.MySql" Version="$(AspirePackageVersion)" />
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="$(AspirePackageVersion)" />
@ -200,7 +200,7 @@
<PackageVersion Include="Aspire.Pomelo.EntityFrameworkCore.MySql" Version="$(AspirePackageVersion)" />
<PackageVersion Include="Aspire.StackExchange.Redis" Version="$(AspirePackageVersion)" />
<PackageVersion Include="Aspire.RabbitMQ.Client" Version="$(AspirePackageVersion)" />
<PackageVersion Include="Aspire.Elastic.Clients.Elasticsearch" Version="13.0.0" />
<PackageVersion Include="Aspire.Elastic.Clients.Elasticsearch" Version="$(AspirePackageVersion)" />
</ItemGroup>
<!-- Elsa -->
<ItemGroup>
@ -276,16 +276,16 @@
</ItemGroup>
<!-- OpenTelemetry -->
<ItemGroup>
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.Zipkin" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.14.0-beta.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Quartz" Version="1.14.0-beta.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.14.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.SqlClient" Version="1.14.0-beta.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Quartz" Version="1.15.1-beta.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.SqlClient" Version="1.15.2" />
</ItemGroup>
<!-- AI -->
<ItemGroup>
@ -318,7 +318,7 @@
<PackageVersion Include="Oracle.ManagedDataAccess.Core" Version="23.6.1" />
<PackageVersion Include="Npgsql" Version="10.0.0" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.1.1" />
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="10.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="10.0.7" />
</ItemGroup>
<!-- Other -->
<ItemGroup>
@ -333,6 +333,10 @@
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.14.0" />
<PackageVersion Include="aliyun-net-sdk-core" Version="1.6.2" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageVersion Include="AlibabaCloud.SDK.Dypnsapi20170525" Version="2.0.0" />
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="4.3.1" />
<PackageVersion Include="AlibabaCloud.SDK.Sts20150401" Version="1.2.0" />
<PackageVersion Include="AlibabaCloud.OSS.V2" Version="0.1.2" />
<PackageVersion Include="AgileConfig.Client" Version="1.8.0" />
<PackageVersion Include="CommonMark.NET" Version="0.15.1" />
<PackageVersion Include="DocumentFormat.OpenXml" Version="3.5.1" />
@ -350,6 +354,7 @@
<PackageVersion Include="JetBrains.Annotations" Version="2025.2.2" />
<PackageVersion Include="Magicodes.IE.Excel" Version="2.8.2" />
<PackageVersion Include="Markdig" Version="0.44.0" />
<PackageVersion Include="MimeCheck" Version="1.0.0" />
<PackageVersion Include="MiniExcel" Version="1.43.0" />
<PackageVersion Include="MiniWord" Version="0.9.2" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
@ -360,8 +365,8 @@
<PackageVersion Include="OllamaSharp" Version="5.4.20" />
<PackageVersion Include="ModelContextProtocol" Version="1.1.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.74.0-alpha" />
<PackageVersion Include="OpenIddict.Server.DataProtection" Version="7.2.0" />
<PackageVersion Include="OpenIddict.Validation.DataProtection" Version="7.2.0" />
<PackageVersion Include="OpenIddict.Server.DataProtection" Version="7.5.0" />
<PackageVersion Include="OpenIddict.Validation.DataProtection" Version="7.5.0" />
<PackageVersion Include="Polly" Version="8.6.3" />
<PackageVersion Include="QRCoder" Version="1.5.1" />
<PackageVersion Include="Quartz.Serialization.Json" Version="3.15.0" />
@ -378,7 +383,7 @@
<PackageVersion Include="Spire.XLS" Version="15.12.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.0.1" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.0" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.7" />
<PackageVersion Include="Tencent.QCloud.Cos.Sdk" Version="5.4.37" />
<PackageVersion Include="TencentCloudSDK" Version="3.0.1273" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.3.0" />

50
apps/vben5/apps/app-antd/src/layouts/basic.vue

@ -1,10 +1,10 @@
<script lang="ts" setup>
import type { NotificationItem } from '@vben/layouts';
import { computed, ref, watch } from 'vue';
import { computed, defineAsyncComponent, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
import { AuthenticationLoginExpiredModal, useVbenModal } from '@vben/common-ui';
import { useWatermark } from '@vben/hooks';
import { createIconifyIcon } from '@vben/icons';
import {
@ -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';
@ -24,25 +24,41 @@ import { useAuthStore } from '#/store';
import LoginForm from '#/views/_core/authentication/login.vue';
const UserSettingsIcon = createIconifyIcon('tdesign:user-setting');
const UserLinkIcon = createIconifyIcon('material-symbols-light:link');
const notifications = ref<NotificationItem[]>([]);
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),
);
const [LinkUserModal, linkUserModalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(async () => {
const res = await import('@abp/account');
return res.UserLinkModal;
}),
});
const menus = computed(() => [
{
handler: () => {
replace('/account/my-settings');
linkUserModalApi.open();
},
icon: UserLinkIcon,
text: $t('abp.account.linkAccount'),
},
{
handler: () => {
router.replace('/account/my-settings');
},
icon: UserSettingsIcon,
text: $t('abp.account.settings.title'),
@ -75,6 +91,29 @@ function handleNoticeClear() {
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
async function handleLinkUser(token: string) {
const { currentUser, currentTenant } = abpStore.application!;
const extraQueryParams: Record<string, string> = {
LinkUserId: currentUser.id!,
LinkToken: token,
};
if (currentTenant.id) {
extraQueryParams.LinkTenantId = currentTenant.id;
}
// 跳转登录页,交由后端处理
await authStore.oidcLogin({
prompt: 'login',
extraQueryParams,
});
}
async function handleLinkLogin(userId: string, tenantId?: string) {
await authStore.linkUseLogin(userId, tenantId, () => {
tabbarStore.closeAllTabs(router);
window.location.replace('/');
});
}
watch(
() => preferences.app.watermark,
async (enable) => {
@ -108,6 +147,7 @@ watch(
{{ description }}
</span>
</div>
<LinkUserModal @link="handleLinkUser" @login="handleLinkLogin" />
</template>
<template #notification>
<Notification

1
apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json

@ -79,6 +79,7 @@
},
"account": {
"title": "Account",
"linkAccount": "Link Account",
"settings": {
"title": "My Settings",
"basic": {

1
apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json

@ -79,6 +79,7 @@
},
"account": {
"title": "账户管理",
"linkAccount": "关联账户",
"settings": {
"title": "个人设置",
"basic": {

40
apps/vben5/apps/app-antd/src/store/auth.ts

@ -1,4 +1,4 @@
import type { OAuthError, TokenResult } from '@abp/account';
import type { OAuthError, SigninRedirectArgs, TokenResult } from '@abp/account';
import type { Recordable, UserInfo } from '@vben/types';
@ -47,8 +47,8 @@ export const useAuthStore = defineStore('auth', () => {
}
}
async function oidcLogin() {
await oAuthService.login();
async function oidcLogin(args?: SigninRedirectArgs) {
await oAuthService.login(args);
}
async function oidcCallback(onError?: (error: OAuthError) => void) {
@ -114,6 +114,34 @@ export const useAuthStore = defineStore('auth', () => {
}
}
async function linkUseLogin(
userId: string,
tenantId?: string,
onSuccess?: () => Promise<void> | void,
) {
try {
loginLoading.value = true;
const accessToken = await oAuthService.getAccessToken();
const user = await oAuthService.loginByLinkUser({
accessToken,
linkUserId: userId,
linkTenantId: tenantId,
});
return await _loginSuccess(
{
accessToken: user.access_token,
tokenType: user.token_type,
refreshToken: user.refresh_token ?? '',
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expiresIn: user.expires_in!,
},
onSuccess,
);
} finally {
loginLoading.value = false;
}
}
/**
* 异步处理登录操作
* Asynchronously handle the login process
@ -175,11 +203,14 @@ export const useAuthStore = defineStore('auth', () => {
if (user) {
userInfoRes = user.profile;
}
const abpConfig = await getConfigApi();
const abpConfig = await getConfigApi({
includeLocalizationResources: false,
});
userInfo = {
userId: userInfoRes.sub ?? abpConfig.currentUser.id,
username: userInfoRes.uniqueName ?? abpConfig.currentUser.userName,
realName:
userInfoRes.given_name ??
userInfoRes.name ??
abpConfig.currentUser.name ??
abpConfig.currentUser.userName,
@ -268,6 +299,7 @@ export const useAuthStore = defineStore('auth', () => {
oidcLogin,
oidcCallback,
fetchUserInfo,
linkUseLogin,
loginLoading,
logout,
refreshSession,

14
apps/vben5/apps/app-antd/src/views/_core/authentication/login.vue

@ -5,6 +5,7 @@ import type { ExtendedFormApi, VbenFormSchema } from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import { computed, nextTick, onMounted, useTemplateRef } from 'vue';
import { useRoute } from 'vue-router';
import { AuthenticationLogin, useVbenModal, z } from '@vben/common-ui';
import { useAppConfig } from '@vben/hooks';
@ -30,6 +31,7 @@ const { auth } = useAppConfig(import.meta.env, import.meta.env.PROD);
const abpStore = useAbpStore();
const authStore = useAuthStore();
const route = useRoute();
const { isTrue } = useSettings();
@ -83,6 +85,12 @@ const [ShouldChangePasswordModal, changePasswordModalApi] = useVbenModal({
});
async function onInit() {
if (auth.onlyOidc === true) {
const query: Record<string, string> = {};
Object.keys(route.query).forEach((key) => {
if (typeof route.query[key] === 'string') {
query[key] = route.query[key];
}
});
if (auth.onlyOidcHint) {
setTimeout(() => {
Modal.confirm({
@ -95,16 +103,16 @@ async function onInit() {
disabled: true,
},
async onOk() {
await authStore.oidcLogin();
await authStore.oidcLogin(query);
},
});
}, 300);
} else {
await authStore.oidcLogin();
await authStore.oidcLogin(query);
}
return;
}
const abpConfig = await getConfigApi();
const abpConfig = await getConfigApi({ includeLocalizationResources: false });
abpStore.setApplication(abpConfig);
nextTick(() => {
const formApi = login.value?.getFormApi();

1
apps/vben5/packages/@abp/account/src/api/index.ts

@ -1,5 +1,6 @@
export { useAccountApi } from './useAccountApi';
export { useExternalLoginsApi } from './useExternalLoginsApi';
export { useLinkUsersApi } from './useLinkUsersApi';
export { useMySessionApi } from './useMySessionApi';
export { useProfileApi } from './useProfileApi';
export { useScanQrCodeApi } from './useScanQrCodeApi';

54
apps/vben5/packages/@abp/account/src/api/useLinkUsersApi.ts

@ -0,0 +1,54 @@
import type { ListResultDto } from '@abp/core';
import type { LinkUserDto, UnLinkUserInput } from '../types/link-user';
import { useRequest } from '@abp/request';
export function useLinkUsersApi() {
const { cancel, request } = useRequest();
/**
* 查询关联用户列表
* @returns { Promise<ListResultDto<LinkUserDto>> } 关联用户列表
*/
function getListApi(): Promise<ListResultDto<LinkUserDto>> {
return request<ListResultDto<LinkUserDto>>('api/account/link-users', {
method: 'GET',
});
}
/**
* 生成关联用户Token
*/
function generateLinkTokenApi(): Promise<string> {
return request(`api/account/link-users/generate-link-token`, {
method: 'POST',
});
}
/**
* 生成关联用户登录Token
*/
function generateLinkLoginTokenApi(): Promise<string> {
return request(`api/account/link-users/generate-link-login-token`, {
method: 'POST',
});
}
/**
* 取消用户关联
* @param input 参数
*/
function unLinkApi(input: UnLinkUserInput): Promise<void> {
return request(`api/account/link-users/unlink`, {
method: 'POST',
data: input,
});
}
return {
cancel,
getListApi,
generateLinkTokenApi,
generateLinkLoginTokenApi,
unLinkApi,
};
}

198
apps/vben5/packages/@abp/account/src/components/UserLinkModal.vue

@ -0,0 +1,198 @@
<script setup lang="ts">
import type { VxeGridProps } from '@abp/ui';
import type { LinkUserDto } from '../types';
import { h, ref } from 'vue';
import { confirm, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { sortby } from '@abp/core';
import { useMessage, useVbenVxeGrid } from '@abp/ui';
import {
CheckOutlined,
CloseOutlined,
DeleteOutlined,
LoginOutlined,
PlusOutlined,
} from '@ant-design/icons-vue';
import { Button } from 'ant-design-vue';
import { useLinkUsersApi } from '../api/useLinkUsersApi';
const emit = defineEmits<{
(event: 'link', token: string): void;
(event: 'login', userId: string, tenantId?: string): void;
}>();
const message = useMessage();
const { getListApi, generateLinkTokenApi, unLinkApi } = useLinkUsersApi();
const linkUsers = ref<LinkUserDto[]>([]);
const [Modal, modalApi] = useVbenModal({
async onOpenChange(isOpen) {
if (isOpen) {
await onInit();
}
},
title: $t('AbpAccount.LinkUser'),
});
const gridOptions: VxeGridProps<LinkUserDto> = {
columns: [
{
align: 'left',
field: 'linkUserName',
formatter: ({ row }) => {
if (row.linkTenantName) {
return `${row.linkTenantName}/${row.linkUserName}`;
}
return row.linkUserName;
},
sortable: true,
title: $t('AbpAccount.DisplayName:LinkUserName'),
},
{
align: 'left',
field: 'directlyLinked',
slots: { default: 'directlyLinked' },
sortable: true,
title: $t('AbpAccount.DisplayName:DirectlyLinked'),
width: 150,
},
{
field: 'actions',
fixed: 'right',
slots: { default: 'actions' },
title: $t('AbpUi.Actions'),
width: 220,
},
],
exportConfig: {},
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page, sort }) => {
let items = sortby(linkUsers.value, sort.field);
if (sort.order === 'desc') {
items = items.toReversed();
}
const result = {
totalCount: linkUsers.value.length,
items: items.slice(
(page.currentPage - 1) * page.pageSize,
page.currentPage * page.pageSize,
),
};
return new Promise((resolve) => {
resolve(result);
});
},
},
response: {
total: 'totalCount',
list: 'items',
},
},
sortConfig: {
remote: true,
allowBtn: true,
},
toolbarConfig: {
custom: true,
export: true,
zoom: true,
},
};
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions,
});
async function onInit() {
const { items } = await getListApi();
linkUsers.value = items;
gridApi.query();
}
async function onCreatLink() {
confirm({
async beforeClose(scope) {
if (scope.isConfirm) {
const token = await generateLinkTokenApi();
emit('link', token);
}
},
centered: true,
content: $t('AbpAccount.LinkAccountWillBeCreateWarning'),
title: $t('AbpUi.AreYouSure'),
});
}
function onLoginByLink(record: LinkUserDto) {
emit('login', record.linkUserId, record.linkTenantId);
modalApi.close();
}
async function onDeleteLink(record: LinkUserDto) {
confirm({
async beforeClose(scope) {
if (scope.isConfirm) {
await unLinkApi({
userId: record.linkUserId,
tenantId: record.linkTenantId,
});
message.success($t('AbpUi.DeletedSuccessfully'));
await onInit();
}
},
centered: true,
content: $t('AbpAccount.LinkAccountWillBeDeleteWarning', [
record.linkUserName,
]),
title: $t('AbpUi.AreYouSure'),
});
}
</script>
<template>
<Modal>
<Grid>
<template #toolbar-tools>
<Button :icon="h(PlusOutlined)" type="primary" @click="onCreatLink">
{{ $t('AbpAccount.LinkUser:New') }}
</Button>
</template>
<template #directlyLinked="{ row }">
<div class="flex flex-row justify-center">
<CheckOutlined v-if="row.directlyLinked" class="text-green-500" />
<CloseOutlined v-else class="text-red-500" />
</div>
</template>
<template #actions="{ row }">
<div class="flex flex-row">
<Button
:icon="h(LoginOutlined)"
block
type="link"
@click="onLoginByLink(row)"
>
{{ $t('AbpAccount.LinkUser:Login') }}
</Button>
<Button
:icon="h(DeleteOutlined)"
block
danger
type="link"
@click="onDeleteLink(row)"
>
{{ $t('AbpUi.Delete') }}
</Button>
</div>
</template>
</Grid>
</Modal>
</template>
<style scoped></style>

1
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';

16
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,

2
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';

14
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 };

10
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,

25
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;

3
apps/vben5/packages/@abp/ai-management/src/components/tools/AIToolDefinitionTable.vue

@ -140,7 +140,8 @@ const gridOptions: VxeGridProps<AIToolDefinitionRecordDto> = {
custom: true,
export: true,
// import: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/ai-management/src/components/workspaces/WorkspaceDefinitionTable.vue

@ -130,7 +130,8 @@ const gridOptions: VxeGridProps<WorkspaceDefinitionRecordDto> = {
custom: true,
export: true,
// import: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue

@ -241,7 +241,8 @@ const gridOptions: VxeGridProps<AuditLogDto> = {
custom: true,
export: true,
// import: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

2
apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue

@ -219,7 +219,7 @@ async function onGet(id: string) {
{{ row.hResult }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.HelpURL')">
{{ row.helpURL }}
{{ row.helpUrl }}
</DescriptionsItem>
</Descriptions>
</template>

3
apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue

@ -278,7 +278,8 @@ const gridOptions: VxeGridProps<LogDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

5
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:"
}

26
apps/vben5/packages/@abp/blob-management/src/api/useBlobsApi.ts

@ -32,8 +32,26 @@ export function useBlobsApi() {
});
}
function getContentApi(id: string): Promise<Blob> {
return request<Blob>(`/api/blob-management/blobs/uid/${id}/content`, {
function generateDownloadUrlApi(id: string): Promise<string> {
return request<string>(
`/api/blob-management/blobs/generate/download-url/${id}`,
{
method: 'GET',
},
);
}
function generatePreviewUrlApi(id: string): Promise<string> {
return request<string>(
`/api/blob-management/blobs/generate/preview-url/${id}`,
{
method: 'GET',
},
);
}
function downloadApi(id: string): Promise<Blob> {
return request<Blob>(`/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,

4
apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal.vue

@ -64,7 +64,7 @@ const blobType = ref<FileType>();
const errorMessage = ref<string>('');
const excelComponentKey = ref(0); // 只对 Excel 组件使用 key
const { getContentApi } = useBlobsApi();
const { downloadApi } = useBlobsApi();
// 文件类型配置
const allowFiles: Record<FileType, string[]> = {
@ -175,7 +175,7 @@ async function onInit() {
}
// 获取文件内容
const content = await getContentApi(blob.value.id);
const content = await downloadApi(blob.value.id);
// 检查文件大小
if (!isFileSizeValid(content)) {

106
apps/vben5/packages/@abp/blob-management/src/components/blobs/BlobFilePreviewModal1.vue

@ -0,0 +1,106 @@
<script setup lang="ts">
import type { BlobDto } from '../../types/blobs';
import { defineAsyncComponent, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { downloadFileFromUrl } from '@vben/utils';
import { Button, Spin } from 'ant-design-vue';
import { useBlobsApi } from '../../api/useBlobsApi';
const VueFilesPreview = defineAsyncComponent({
loader: async () => {
const res = await import('vue-files-preview');
import('vue-files-preview/lib/style.css');
return res.VueFilesPreview;
},
loadingComponent: Spin,
delay: 200,
});
const fileName = ref<string>();
const previewUrl = ref<string>();
const errorMsg = ref<string>();
const { generatePreviewUrlApi } = useBlobsApi();
const [Modal, modalApi] = useVbenModal({
showCancelButton: false,
showConfirmButton: false,
fullscreen: true,
fullscreenButton: false,
onOpenChange: async (isOpen) => {
isOpen && onInit();
},
onClosed() {
previewUrl.value = undefined;
fileName.value = undefined;
errorMsg.value = undefined;
},
});
async function onInit() {
try {
modalApi.lock();
const blob = modalApi.getData<BlobDto>();
fileName.value = blob.name;
previewUrl.value = await generatePreviewUrlApi(blob.id);
} finally {
modalApi.unlock();
}
}
async function handleDownload() {
downloadFileFromUrl({
fileName: fileName.value!,
source: previewUrl.value!,
});
}
function onError(error: Error) {
errorMsg.value = error.message;
}
</script>
<template>
<Modal :title="fileName">
<div class="preview-container">
<VueFilesPreview
v-if="previewUrl"
:url="previewUrl"
:name="fileName"
@error="onError"
/>
<!-- 下载按钮 -->
<div v-if="errorMsg && previewUrl" class="download-button">
<Button type="primary" @click="handleDownload">
{{ $t('BlobManagement.Blobs:Download') }}
</Button>
</div>
</div>
</Modal>
</template>
<style scoped lang="scss">
.preview-container {
position: relative;
height: 100%;
.error-message {
padding: 40px 20px;
text-align: center;
}
.download-button {
position: sticky;
right: 20px;
bottom: 20px;
z-index: 10;
float: right;
margin-top: 20px;
}
}
</style>

9
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<string[]>([]);
@ -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'),

3
apps/vben5/packages/@abp/blob-management/src/components/containers/BlobContainerTable.vue

@ -109,7 +109,8 @@ const gridOptions: VxeGridProps<BlobContainerDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/data-protection/src/components/entity-type-infos/EntityTypeInfoTable.vue

@ -91,7 +91,8 @@ const gridOptions: VxeGridProps<EntityTypeInfoDto> = {
},
},
toolbarConfig: {
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
},

3
apps/vben5/packages/@abp/demo/src/components/books/BookTable.vue

@ -108,7 +108,8 @@ const gridOptions: VxeGridProps<BookDto> = {
},
},
toolbarConfig: {
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
},

2
apps/vben5/packages/@abp/features/src/components/features/FeatureModal.vue

@ -269,7 +269,7 @@ async function onSubmit() {
<style lang="scss" scoped>
:deep(.ant-tabs) {
height: 34rem;
height: 60vh;
.ant-tabs-nav {
width: 14rem;

3
apps/vben5/packages/@abp/gdpr/src/components/GdprTable.vue

@ -84,7 +84,8 @@ const gridOptions: VxeGridProps<GdprRequestDto> = {
},
},
toolbarConfig: {
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
},

3
apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue

@ -154,7 +154,8 @@ const gridOptions: VxeGridProps<IdentityClaimTypeDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitRoleTable.vue

@ -84,7 +84,8 @@ const gridOptions: VxeGridProps<IdentityRoleDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue

@ -90,7 +90,8 @@ const gridOptions: VxeGridProps<IdentityUserDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/identity/src/components/organization-units/SelectMemberModal.vue

@ -112,7 +112,8 @@ const gridOptions: VxeGridProps<IdentityUserDto> = {
},
},
toolbarConfig: {
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
},

3
apps/vben5/packages/@abp/identity/src/components/organization-units/SelectRoleModal.vue

@ -104,7 +104,8 @@ const gridOptions: VxeGridProps<IdentityRoleDto> = {
},
},
toolbarConfig: {
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
},

3
apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue

@ -120,7 +120,8 @@ const gridOptions: VxeGridProps<IdentityRoleDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue

@ -185,7 +185,8 @@ const gridOptions: VxeGridProps<SecurityLogDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/identity/src/components/sessions/SessionTable.vue

@ -168,7 +168,8 @@ const gridOptions: VxeGridProps<IdentitySessionDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue

@ -168,7 +168,8 @@ const gridOptions: VxeGridProps<IdentityUserDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/notifications/src/components/my-notifilers/MyNotificationTable.vue

@ -175,7 +175,8 @@ const gridOptions: VxeGridProps<Notification> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/notifications/src/components/send-records/NotificationSendRecordTable.vue

@ -234,7 +234,8 @@ const gridOptions: VxeGridProps<NotificationSendRecordDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationTable.vue

@ -146,7 +146,8 @@ const gridOptions: VxeGridProps<OpenIddictApplicationDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/openiddict/src/components/authorizations/AuthorizationTable.vue

@ -168,7 +168,8 @@ const gridOptions: VxeGridProps<OpenIddictAuthorizationDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/openiddict/src/components/scopes/ScopeTable.vue

@ -121,7 +121,8 @@ const gridOptions: VxeGridProps<OpenIddictScopeDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/openiddict/src/components/tokens/TokenTable.vue

@ -195,7 +195,8 @@ const gridOptions: VxeGridProps<OpenIddictTokenDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue

@ -120,7 +120,8 @@ const gridOptions: VxeGridProps<OssContainerDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue

@ -150,7 +150,8 @@ const gridOptions: VxeGridProps<OssObjectDto> = {
toolbarConfig: {
custom: true,
export: false,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

2
apps/vben5/packages/@abp/permissions/src/components/permissions/PermissionModal.vue

@ -323,7 +323,7 @@ function getChildren(permissions: PermissionTree[]): PermissionTree[] {
<style lang="scss" scoped>
:deep(.ant-tabs) {
height: 34rem;
height: 60vh;
.ant-tabs-nav {
width: 14rem;

3
apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue

@ -144,7 +144,8 @@ const gridOptions: VxeGridProps<LayoutDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/platform/src/components/messages/email/EmailMessageTable.vue

@ -207,7 +207,8 @@ const gridOptions: VxeGridProps<EmailMessageDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/platform/src/components/messages/sms/SmsMessageTable.vue

@ -188,7 +188,8 @@ const gridOptions: VxeGridProps<SmsMessageDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/saas/src/components/editions/EditionTable.vue

@ -103,7 +103,8 @@ const gridOptions: VxeGridProps<EditionDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/saas/src/components/tenants/TenantTable.vue

@ -128,7 +128,8 @@ const gridOptions: VxeGridProps<TenantDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

1
apps/vben5/packages/@abp/settings/package.json

@ -25,6 +25,7 @@
"@abp/request": "workspace:*",
"@abp/ui": "workspace:*",
"@ant-design/icons-vue": "catalog:",
"@vben-core/shadcn-ui": "workspace:*",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/hooks": "workspace:*",

2
apps/vben5/packages/@abp/settings/src/api/useDefinitionsApi.ts

@ -96,7 +96,7 @@ export function useDefinitionsApi() {
ListResultDto<NameValue<string>>
> {
return request<ListResultDto<NameValue<string>>>(
'/api/permission-management/definitions/assignable-providers',
'/api/setting-management/settings/definitions/assignable-providers',
{
method: 'GET',
},

30
apps/vben5/packages/@abp/settings/src/api/useSettingsApi.ts

@ -6,6 +6,30 @@ import { useRequest } from '@abp/request';
export function useSettingsApi() {
const { cancel, request } = useRequest();
/**
* 获取设置
* @returns 设置数据传输对象列表
*/
function getSettingsApi(): Promise<ListResultDto<SettingGroup>> {
return request<ListResultDto<SettingGroup>>(
`/api/v2/setting-management/settings`,
{
method: 'GET',
},
);
}
/**
* 变更设置
* @returns 设置数据传输对象列表
*/
function setSettingsApi(input: SettingsUpdateInput): Promise<void> {
return request(`/api/v2/setting-management/settings`, {
data: input,
method: 'PUT',
});
}
/**
* 获取全局设置
* @returns 设置数据传输对象列表
@ -59,7 +83,7 @@ export function useSettingsApi() {
*/
function getUserSettingsApi(): Promise<ListResultDto<SettingGroup>> {
return request<ListResultDto<SettingGroup>>(
`/api/setting-management/settings/by-current-user`,
`/api/v2/setting-management/my-settings`,
{
method: 'GET',
},
@ -71,7 +95,7 @@ export function useSettingsApi() {
* @returns 设置数据传输对象列表
*/
function setUserSettingsApi(input: SettingsUpdateInput): Promise<void> {
return request(`/api/setting-management/settings/change-current-user`, {
return request(`/api/v2/setting-management/my-settings`, {
data: input,
method: 'PUT',
});
@ -92,6 +116,8 @@ export function useSettingsApi() {
return {
cancel,
getSettingsApi,
setSettingsApi,
getGlobalSettingsApi,
getTenantSettingsApi,
getUserSettingsApi,

42
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);
</script>
@ -124,12 +132,8 @@ onMounted(onGet);
</Button>
</div>
</template>
<Form
:label-col="{ span: 5 }"
:wrapper-col="{ span: 15 }"
class="h-[700px] overflow-y-scroll"
>
<Tabs v-model="activeTab">
<Form :label-col="{ span: 5 }" :wrapper-col="{ span: 15 }">
<Tabs tab-position="left" type="card" v-model="activeTab">
<TabPane
v-for="(group, index) in settingGroups"
:key="index"
@ -194,16 +198,20 @@ onMounted(onGet);
<Select
v-if="detail.valueType === ValueType.Option"
v-model:value="detail.value"
:filter-option="onFilterOption"
:field-names="{ label: 'name', value: 'value' }"
:options="detail.options"
show-search
@change="onValueChange(detail)"
>
<SelectOption
/>
<!-- <SelectOption
v-for="option in detail.options"
:key="option.value"
:disabled="option.value === detail.value"
>
{{ option.name }}
</SelectOption>
</Select>
</Select> -->
<Checkbox
v-if="detail.valueType === ValueType.Boolean"
:checked="detail.value?.toLowerCase() === 'true'"
@ -221,4 +229,16 @@ onMounted(onGet);
</Card>
</template>
<style scoped></style>
<style lang="scss" scoped>
:deep(.ant-tabs) {
height: 75vh;
.ant-tabs-nav {
width: 14rem;
}
.ant-tabs-content-holder {
overflow: hidden auto !important;
}
}
</style>

21
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) {

51
apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoDrawer.vue

@ -27,7 +27,7 @@ import {
} from 'ant-design-vue';
import { useJobInfosApi } from '../../api/useJobInfosApi';
import { JobPriority, JobType } from '../../types/job-infos';
import { JobPriority, JobSource, JobType } from '../../types/job-infos';
defineOptions({
name: 'JobInfoDrawer',
@ -40,6 +40,9 @@ interface JobParamter {
key: string;
value: any;
}
interface ModalState extends BackgroundJobInfoDto {
isCopy?: boolean;
}
const activedTab = ref('basic');
const jobTypeOptions = reactive([
@ -79,6 +82,7 @@ const jobPriorityOptions = reactive([
},
]);
const jobDefinetions = ref<BackgroundJobDefinitionDto[]>([]);
const jobArgsDisplayNameMap = ref<Record<string, string>>({});
const form = useTemplateRef<FormInstance>('form');
const formModel = ref<BackgroundJobInfoDto>({} as BackgroundJobInfoDto);
const { createApi, getApi, getDefinitionsApi, updateApi } = useJobInfosApi();
@ -101,9 +105,9 @@ const [Drawer, drawerApi] = useVbenDrawer({
priority: JobPriority.Normal,
} as BackgroundJobInfoDto;
drawerApi.setState({ loading: true });
const dto = drawerApi.getData<BackgroundJobInfoDto>();
if (dto?.id) {
await onGet(dto.id);
const state = drawerApi.getData<ModalState>();
if (state?.id) {
await onGet(state.id, state.isCopy);
} else {
await onInitDefaultJobs();
drawerApi.setState({
@ -117,12 +121,23 @@ const [Drawer, drawerApi] = useVbenDrawer({
},
title: $t('BackgroundJobs:Edit'),
});
async function onGet(id: string) {
async function onGet(id: string, isCopy?: boolean) {
const dto = await getApi(id);
if (isCopy === true) {
dto.id = '';
dto.name = '';
dto.source = JobSource.User;
drawerApi.setState({
title: $t('TaskManagement.BackgroundJobs:AddNew'),
});
await onInitDefaultJobs();
} else {
drawerApi.setState({
title: `${$t('TaskManagement.BackgroundJobs:Edit')} - ${dto.name}`,
});
}
formModel.value = dto;
drawerApi.setState({
title: `${$t('TaskManagement.BackgroundJobs:Edit')} - ${dto.name}`,
});
}
async function onInitDefaultJobs() {
@ -148,14 +163,18 @@ async function onSubmit() {
function onJobDefineChange(jobName: string) {
formModel.value.args = {};
jobArgsDisplayNameMap.value = {};
const jobDefine = jobDefinetions.value.find((x) => x.name === jobName);
if (jobDefine) {
const params: Record<string, any> = {};
const paramDisplayNames: Record<string, any> = {};
jobDefine.paramters.forEach((param) => {
params[param.name] = undefined;
paramDisplayNames[param.name] = param.displayName;
});
formModel.value.args = params;
formModel.value.type = jobDefine.name;
jobArgsDisplayNameMap.value = paramDisplayNames;
}
}
@ -206,6 +225,7 @@ function onDeleteParam(record: JobParamter) {
>
<Input
v-model:value="formModel.nodeName"
:disabled="!!formModel.id"
allow-clear
autocomplete="off"
/>
@ -217,6 +237,7 @@ function onDeleteParam(record: JobParamter) {
>
<Input
v-model:value="formModel.group"
:disabled="!!formModel.id"
allow-clear
autocomplete="off"
/>
@ -228,6 +249,7 @@ function onDeleteParam(record: JobParamter) {
>
<Input
v-model:value="formModel.name"
:disabled="!!formModel.id"
allow-clear
autocomplete="off"
/>
@ -241,6 +263,7 @@ function onDeleteParam(record: JobParamter) {
<Textarea
allow-clear
v-model:value="formModel.type"
:disabled="!!formModel.id"
:auto-size="{ minRows: 3 }"
/>
</FormItem>
@ -280,7 +303,16 @@ function onDeleteParam(record: JobParamter) {
/>
</FormItem>
<FormItem
v-if="formModel.jobType === JobType.Period"
v-if="formModel.jobType === JobType.Persistent"
name="interval"
required
:label="$t('TaskManagement.DisplayName:Interval')"
:extra="$t('TaskManagement.Description:Interval')"
>
<InputNumber class="w-full" v-model:value="formModel.interval" />
</FormItem>
<FormItem
v-else-if="formModel.jobType === JobType.Period"
name="cron"
required
:label="$t('TaskManagement.DisplayName:Cron')"
@ -347,6 +379,7 @@ function onDeleteParam(record: JobParamter) {
<TabPane key="paramters" :tab="$t('TaskManagement.Paramters')">
<PropertyTable
:data="formModel.args"
:display-name-map="jobArgsDisplayNameMap"
@change="onEditParam"
@delete="onDeleteParam"
/>

21
apps/vben5/packages/@abp/tasks/src/components/job-infos/JobInfoTable.vue

@ -16,6 +16,7 @@ import { $t } from '@vben/locales';
import { formatToDateTime } from '@abp/core';
import { useVbenVxeGrid } from '@abp/ui';
import {
CopyOutlined,
DeleteOutlined,
EditOutlined,
EllipsisOutlined,
@ -25,6 +26,7 @@ import {
Button,
Dropdown,
Menu,
MenuDivider,
MenuItem,
message,
Modal,
@ -387,7 +389,8 @@ const gridOptions: VxeGridProps<BackgroundJobInfoDto> = {
},
},
toolbarConfig: {
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
},
@ -515,6 +518,14 @@ function onBulkStart() {
function onMenuClick(row: BackgroundJobInfoDto, info: MenuInfo) {
switch (info.key) {
case 'copy': {
jobDrawerApi.setData({
...row,
isCopy: true,
});
jobDrawerApi.open();
break;
}
case 'pause': {
onJobStatusChange(
row,
@ -722,6 +733,14 @@ function onJobStatusChange(
>
{{ $t('TaskManagement.BackgroundJobs:Stop') }}
</MenuItem>
<MenuDivider />
<MenuItem
v-if="hasAccessByCodes([BackgroundJobsPermissions.Create])"
key="copy"
:icon="h(CopyOutlined)"
>
{{ $t('TaskManagement.BackgroundJobs:Copy') }}
</MenuItem>
</Menu>
</template>
<Button :icon="h(EllipsisOutlined)" type="link" />

10
apps/vben5/packages/@abp/tasks/src/types/job-infos.ts

@ -35,8 +35,7 @@ enum JobSource {
}
interface BackgroundJobInfoDto
extends ExtensibleAuditedEntityDto<string>,
IHasConcurrencyStamp {
extends ExtensibleAuditedEntityDto<string>, IHasConcurrencyStamp {
args: Record<string, any>;
beginTime: string;
cron?: string;
@ -53,6 +52,7 @@ interface BackgroundJobInfoDto
maxTryCount: number;
name: string;
nextRunTime?: string;
nodeName?: string;
priority: JobPriority;
result?: string;
source: JobSource;
@ -75,8 +75,7 @@ interface BackgroundJobInfoCreateOrUpdateDto {
priority: JobPriority;
}
interface BackgroundJobInfoCreateDto
extends BackgroundJobInfoCreateOrUpdateDto {
interface BackgroundJobInfoCreateDto extends BackgroundJobInfoCreateOrUpdateDto {
beginTime: string;
endTime?: string;
group: string;
@ -87,8 +86,7 @@ interface BackgroundJobInfoCreateDto
}
interface BackgroundJobInfoUpdateDto
extends BackgroundJobInfoCreateOrUpdateDto,
IHasConcurrencyStamp {}
extends BackgroundJobInfoCreateOrUpdateDto, IHasConcurrencyStamp {}
interface BackgroundJobInfoGetListInput extends PagedAndSortedResultRequestDto {
beginCreationTime?: Date;

20
apps/vben5/packages/@abp/ui/src/components/properties/PropertyTable.vue

@ -46,8 +46,7 @@ const getTableColumns = computed((): TableColumnsType<PropertyInfo> => {
{
align: 'left',
dataIndex: 'key',
fixed: 'left',
width: 100,
width: 150,
title: $t('component.extra_property_dictionary.key'),
customRender: (opt) => {
if (props.renderKey && isFunction(props.renderKey)) {
@ -58,8 +57,8 @@ const getTableColumns = computed((): TableColumnsType<PropertyInfo> => {
{
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<PropertyInfo> => {
fixed: 'right',
key: 'action',
title: $t('component.extra_property_dictionary.actions.title'),
width: 150,
width: 200,
},
] as TableColumnsType<PropertyInfo>)),
];
@ -122,7 +121,16 @@ function onChange(prop: Record<string, string>) {
<div class="justify-center">
<Table bordered :columns="getTableColumns" :data-source="getDataResource">
<template #bodyCell="{ record, column }">
<template v-if="column.dataIndex === 'action'">
<template v-if="column.dataIndex === 'key'">
<div class="flex flex-col">
<span>{{ record.key }}</span>
<span
v-if="props.displayNameMap && props.displayNameMap[record.key]"
>{{ props.displayNameMap[record.key] }}
</span>
</div>
</template>
<template v-else-if="column.dataIndex === 'action'">
<div class="flex flex-row">
<Button
v-if="!props.disabled && props.allowEdit"

1
apps/vben5/packages/@abp/ui/src/components/properties/types.ts

@ -11,6 +11,7 @@ interface PropertyProps {
allowEdit?: boolean;
data?: Dictionary<string, string>;
disabled?: boolean;
displayNameMap?: Dictionary<string, string>;
renderKey?: (key: string) => string | VNode;
}

3
apps/vben5/packages/@abp/webhooks/src/components/send-attempts/WebhookSendAttemptTable.vue

@ -211,7 +211,8 @@ const gridOptions: VxeGridProps<WebhookSendRecordDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

3
apps/vben5/packages/@abp/webhooks/src/components/subscriptions/WebhookSubscriptionTable.vue

@ -210,7 +210,8 @@ const gridOptions: VxeGridProps<WebhookSubscriptionDto> = {
toolbarConfig: {
custom: true,
export: true,
refresh: {
refresh: true,
refreshOptions: {
code: 'query',
},
zoom: true,

15
apps/vben5/packages/@abp/wechat/src/components/bind-user/index.vue

@ -3,11 +3,13 @@ import { useTemplateRef } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { buildUUID } from '@abp/core';
import { buildUUID, useFeatures } from '@abp/core';
import { WWLoginRedirectType, WWLoginType } from '@wecom/jssdk';
import * as ww from '@wecom/jssdk';
import { Empty } from 'ant-design-vue';
import { userWorkWeixinJsSdkApi } from '../../api/userWorkWeixinJsSdkApi';
import { WeixinWorkAuthEnable } from '../../constants/features';
const emits = defineEmits<{
/**
@ -18,6 +20,7 @@ const emits = defineEmits<{
}>();
const wxLoginRef = useTemplateRef<Element>('wxLogin');
const { isEnabled } = useFeatures();
const { getAgentConfigApi } = userWorkWeixinJsSdkApi();
const [Modal, modalApi] = useVbenModal({
@ -54,7 +57,15 @@ async function onInitLogin() {
<template>
<Modal :title="$t('AbpAccountOAuth.OAuth:WorkWeixin')">
<div ref="wxLogin"></div>
<div v-if="isEnabled([WeixinWorkAuthEnable])" ref="wxLogin"></div>
<Empty
v-else
:description="
$t('AbpFeature.Volo.Feature:010001', [
$t('AbpAccountOAuth.Features:WeComOAuthEnable'),
])
"
/>
</Modal>
</template>

2
apps/vben5/packages/@abp/wechat/src/constants/features.ts

@ -0,0 +1,2 @@
/** 启用企业微信认证 */
export const WeixinWorkAuthEnable = 'Abp.Account.OAuth.WeCom.Enable';

2
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

16
aspnet-core/LINGYUN.MicroService.All.slnx

@ -1,6 +1,14 @@
<Solution>
<Folder Name="/.build/">
<File Path="../build/build-aspnetcore-build-sln.ps1" />
<File Path="../build/build-aspnetcore-common.ps1" />
<File Path="../build/build-aspnetcore-publish-sln.ps1" />
<File Path="../build/build-aspnetcore-release-sln.ps1" />
<File Path="../build/package-aspnetcore-publish.ps1" />
</Folder>
<Folder Name="/.changes/">
<File Path="../.changes/Migration 10.0.2 - 10.2.0.md" />
<File Path="../.changes/Migration 10.2.0 - 10.4.0.md" />
</Folder>
<Folder Name="/.github/" />
<Folder Name="/.github/workflows/">
@ -85,6 +93,7 @@
</Folder>
<Folder Name="/framework/" />
<Folder Name="/framework/auditing/">
<Project Path="framework/auditing/LINGYUN.Abp.AspNetCore.Auditing/LINGYUN.Abp.AspNetCore.Auditing.csproj" />
<Project Path="framework/auditing/LINGYUN.Abp.AuditLogging.Elasticsearch/LINGYUN.Abp.AuditLogging.Elasticsearch.csproj" />
<Project Path="framework/auditing/LINGYUN.Abp.AuditLogging.EntityFrameworkCore/LINGYUN.Abp.AuditLogging.EntityFrameworkCore.csproj" />
<Project Path="framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj" />
@ -97,6 +106,9 @@
<Folder Name="/framework/authorization/">
<Project Path="framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/LINGYUN.Abp.Authorization.OrganizationUnits.csproj" />
</Folder>
<Folder Name="/framework/calendars/">
<Project Path="framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj" />
</Folder>
<Folder Name="/framework/cli/">
<Project Path="framework/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj" />
</Folder>
@ -116,6 +128,7 @@
<Folder Name="/framework/common/">
<Project Path="framework/common/LINGYUN.Abp.AspNetCore.HttpOverrides/LINGYUN.Abp.AspNetCore.HttpOverrides.csproj" />
<Project Path="framework/common/LINGYUN.Abp.AspNetCore.Mvc.Client/LINGYUN.Abp.AspNetCore.Mvc.Client.csproj" />
<Project Path="framework/common/LINGYUN.Abp.Core/LINGYUN.Abp.Core.csproj" />
<Project Path="framework/common/LINGYUN.Abp.Data.DbMigrator/LINGYUN.Abp.Data.DbMigrator.csproj" />
<Project Path="framework/common/LINGYUN.Abp.EventBus.CAP/LINGYUN.Abp.EventBus.CAP.csproj" />
<Project Path="framework/common/LINGYUN.Abp.IdGenerator/LINGYUN.Abp.IdGenerator.csproj" />
@ -365,6 +378,7 @@
<Project Path="modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj" />
<Project Path="modules/identity/LINGYUN.Abp.Identity.Session.AspNetCore/LINGYUN.Abp.Identity.Session.AspNetCore.csproj" />
<Project Path="modules/identity/LINGYUN.Abp.Identity.Session/LINGYUN.Abp.Identity.Session.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj" />
</Folder>
<Folder Name="/modules/localization-management/">
<File Path="modules/localization-management/README.md" />
@ -424,6 +438,7 @@
<Project Path="modules/realtime-notifications/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN.Abp.ExceptionHandling.Notifications.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN.Abp.Notifications.Application.Contracts.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN.Abp.Notifications.Application.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Common/LINGYUN.Abp.Notifications.Common.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN.Abp.Notifications.Domain.Shared.csproj" />
@ -471,6 +486,7 @@
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN.Abp.BackgroundTasks.Quartz.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks.TaskManagement/LINGYUN.Abp.BackgroundTasks.TaskManagement.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN.Abp.Elasticsearch.Jobs.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.SqlInstaller/LINGYUN.Abp.Quartz.SqlInstaller.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.TaskManagement.Application.Contracts/LINGYUN.Abp.TaskManagement.Application.Contracts.csproj" />

20
aspnet-core/LINGYUN.MicroService.Aspire.slnx

@ -1,6 +1,7 @@
<Solution>
<Folder Name="/.changes/">
<File Path="../.changes/Migration 10.0.2 - 10.2.0.md" />
<File Path="../.changes/Migration 10.2.0 - 10.4.0.md" />
</Folder>
<Folder Name="/.github/" />
<Folder Name="/.github/workflows/">
@ -90,6 +91,9 @@
<Folder Name="/framework/authorization/">
<Project Path="framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/LINGYUN.Abp.Authorization.OrganizationUnits.csproj" />
</Folder>
<Folder Name="/framework/calendars/">
<Project Path="framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj" Id="2fee90a2-01aa-4417-9529-79bb10b8850c" />
</Folder>
<Folder Name="/framework/cli/">
<Project Path="framework/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj" />
</Folder>
@ -228,10 +232,6 @@
<Project Path="framework/tenants/LINGYUN.Abp.AspNetCore.MultiTenancy/LINGYUN.Abp.AspNetCore.MultiTenancy.csproj" />
<Project Path="framework/tenants/LINGYUN.Abp.MultiTenancy.Editions/LINGYUN.Abp.MultiTenancy.Editions.csproj" />
</Folder>
<Folder Name="/framework/themes/">
<Project Path="framework/themes/LINGYUN.Abp.AspNetCore.Mvc.UI.Theme.Lepton/LINGYUN.Abp.AspNetCore.Mvc.UI.Theme.Lepton.csproj" />
<Project Path="framework/themes/LINGYUN.Abp.Themes.Lepton/LINGYUN.Abp.Themes.Lepton.csproj" />
</Folder>
<Folder Name="/framework/tracking/">
<Project Path="framework/telemetry/LINGYUN.Abp.Telemetry.APM/LINGYUN.Abp.Telemetry.APM.csproj" />
<Project Path="framework/telemetry/LINGYUN.Abp.Telemetry.OpenTelemetry/LINGYUN.Abp.Telemetry.OpenTelemetry.csproj" />
@ -319,7 +319,9 @@
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN.Abp.BlobManagement.FileSystem.csproj" Id="2269c845-fb79-4dde-855d-068bd0df4edf" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi.Client/LINGYUN.Abp.BlobManagement.HttpApi.Client.csproj" Id="94f8b5c9-fcd1-46bc-a521-c794c767da3c" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN.Abp.BlobManagement.HttpApi.csproj" Id="88222f2c-d55f-4d31-9776-e76f880ac052" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN.Abp.BlobManagement.MimeCheck.csproj" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN.Abp.BlobManagement.Minio.csproj" Id="808fb513-aa95-4645-aea9-07634e6c3a86" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN.Abp.BlobManagement.SettingManagement.csproj" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN.Abp.BlobManagement.Tencent.csproj" Id="5d99850b-f8ad-4fa0-bcd4-7f5f455ec5d5" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobStoring.BlobManagement/LINGYUN.Abp.BlobStoring.BlobManagement.csproj" Id="55898e62-9dbe-4569-b7af-b65773408ec5" />
</Folder>
@ -449,6 +451,7 @@
<Project Path="modules/realtime-notifications/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN.Abp.ExceptionHandling.Notifications.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN.Abp.Notifications.Application.Contracts.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN.Abp.Notifications.Application.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj" Id="afef5b69-ebbf-454c-8783-027dde6e5970" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Common/LINGYUN.Abp.Notifications.Common.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN.Abp.Notifications.Domain.Shared.csproj" />
@ -459,6 +462,9 @@
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.HttpApi/LINGYUN.Abp.Notifications.HttpApi.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.SignalR/LINGYUN.Abp.Notifications.SignalR.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Sms/LINGYUN.Abp.Notifications.Sms.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN.Abp.Notifications.Templating.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN.Abp.Notifications.Webhook.WeChat.Work.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN.Abp.Notifications.Webhook.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Notifications.Jobs/LINGYUN.Abp.Notifications.Jobs.csproj" />
</Folder>
@ -495,7 +501,9 @@
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks.Notifications/LINGYUN.Abp.BackgroundTasks.Notifications.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks.Quartz/LINGYUN.Abp.BackgroundTasks.Quartz.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks.TaskManagement/LINGYUN.Abp.BackgroundTasks.TaskManagement.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.BackgroundTasks/LINGYUN.Abp.BackgroundTasks.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Elasticsearch.Jobs/LINGYUN.Abp.Elasticsearch.Jobs.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.PostgresSqlInstaller/LINGYUN.Abp.Quartz.PostgresSqlInstaller.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.SqlInstaller/LINGYUN.Abp.Quartz.SqlInstaller.csproj" />
@ -568,12 +576,10 @@
<Project Path="tests/LINGYUN.Abp.Localization.Xml.Tests/LINGYUN.Abp.Localization.Xml.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.Location.Baidu.Tests/LINGYUN.Abp.Location.Baidu.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.Location.Tencent.Tests/LINGYUN.Abp.Location.Tencent.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.OssManagement.Domain.Tests/LINGYUN.Abp.OssManagement.Domain.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.OssManagement.Minio.Tests/LINGYUN.Abp.OssManagement.Minio.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.OssManagement.Nexus.Tests/LINGYUN.Abp.OssManagement.Nexus.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.Sms.Platform.Tests/LINGYUN.Abp.Sms.Platform.Tests.csproj" />
<Project Path="tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj" />
<Project Path="tests/LINGYUN.Abp.WeChat.Common.Tests/LINGYUN.Abp.WeChat.Common.Tests.csproj" Id="8caa0c21-3cd4-4593-af38-e045113fcd75" />
<Project Path="tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN.Abp.WeChat.Work.Tests.csproj" />
</Folder>
</Solution>

7
aspnet-core/LINGYUN.MicroService.SingleProject.slnx

@ -11,6 +11,7 @@
<Folder Name="/framework/alibaba-cloud/">
<Project Path="framework/cloud-aliyun/LINGYUN.Abp.Aliyun.SettingManagement/LINGYUN.Abp.Aliyun.SettingManagement.csproj" />
<Project Path="framework/cloud-aliyun/LINGYUN.Abp.Aliyun/LINGYUN.Abp.Aliyun.csproj" />
<Project Path="framework/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj" />
<Project Path="framework/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj" />
</Folder>
<Folder Name="/framework/authentication/">
@ -36,6 +37,9 @@
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.SqlInstaller/LINGYUN.Abp.Quartz.SqlInstaller.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj" />
</Folder>
<Folder Name="/framework/calendars/">
<Project Path="framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj" />
</Folder>
<Folder Name="/framework/cap/">
<Project Path="framework/common/LINGYUN.Abp.EventBus.CAP/LINGYUN.Abp.EventBus.CAP.csproj" />
</Folder>
@ -96,6 +100,7 @@
<Project Path="framework/common/LINGYUN.Abp.RealTime/LINGYUN.Abp.RealTime.csproj" />
<Project Path="modules/realtime-message/LINGYUN.Abp.IM.SignalR/LINGYUN.Abp.IM.SignalR.csproj" />
<Project Path="modules/realtime-message/LINGYUN.Abp.IM/LINGYUN.Abp.IM.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Calendar/LINGYUN.Abp.Notifications.Calendar.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Common/LINGYUN.Abp.Notifications.Common.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN.Abp.Notifications.Core.csproj" />
<Project Path="modules/realtime-notifications/LINGYUN.Abp.Notifications.Emailing/LINGYUN.Abp.Notifications.Emailing.csproj" />
@ -207,6 +212,7 @@
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.FileSystem/LINGYUN.Abp.BlobManagement.FileSystem.csproj" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi.Client/LINGYUN.Abp.BlobManagement.HttpApi.Client.csproj" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.HttpApi/LINGYUN.Abp.BlobManagement.HttpApi.csproj" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.MimeCheck/LINGYUN.Abp.BlobManagement.MimeCheck.csproj" Id="bb981955-78c8-45b7-a46a-cc9eefa2166a" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.Minio/LINGYUN.Abp.BlobManagement.Minio.csproj" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.SettingManagement/LINGYUN.Abp.BlobManagement.SettingManagement.csproj" Id="649cb4c3-e7c9-4736-b254-0899bb26bfcb" />
<Project Path="modules/blob-management/LINGYUN.Abp.BlobManagement.Tencent/LINGYUN.Abp.BlobManagement.Tencent.csproj" />
@ -276,6 +282,7 @@
<Project Path="modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj" />
<Project Path="modules/identity/LINGYUN.Abp.Identity.Session.AspNetCore/LINGYUN.Abp.Identity.Session.AspNetCore.csproj" />
<Project Path="modules/identity/LINGYUN.Abp.Identity.Session/LINGYUN.Abp.Identity.Session.csproj" />
<Project Path="modules/task-management/LINGYUN.Abp.Identity.Jobs/LINGYUN.Abp.Identity.Jobs.csproj" />
</Folder>
<Folder Name="/modules/localization-management/">
<Project Path="modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN.Abp.LocalizationManagement.Application.Contracts.csproj" />

2
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/AIServiceModule.cs

@ -14,6 +14,7 @@ using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling.Emailing;
using LINGYUN.Abp.Identity.Session.AspNetCore;
using LINGYUN.Abp.Localization.CultureMap;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.Logging.Serilog.Elasticsearch;
using LINGYUN.Abp.Serilog.Enrichers.Application;
using LINGYUN.Abp.Serilog.Enrichers.UniqueId;
@ -57,6 +58,7 @@ namespace LINGYUN.Abp.MicroService.AIService;
typeof(AbpAIManagementApplicationModule),
typeof(AbpAIManagementHttpApiModule),
typeof(AIServiceMigrationsEntityFrameworkCoreModule),
typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpDataDbMigratorModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpEmailingExceptionHandlingModule),

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AIService/appsettings.Development.json

@ -35,7 +35,8 @@
"CollectorCleaningInterval": 3600000
},
"PostgreSql": {
"TableNamePrefix": "admin",
"Schema": "ai",
"TableNamePrefix": "ai",
"ConnectionString": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
},
"RabbitMQ": {

3
aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService.EntityFrameworkCore/AdminServiceDataSeeder.cs

@ -7,6 +7,7 @@ using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Roles;
namespace LINGYUN.Abp.MicroService.AdminService;
public class AdminServiceDataSeeder : ITransientDependency
@ -49,7 +50,7 @@ public class AdminServiceDataSeeder : ITransientDependency
await PermissionDataSeeder.SeedAsync(
RolePermissionValueProvider.ProviderName,
"admin",
AbpRoleConsts.AdminRoleName,
permissionNames,
context?.TenantId
);

2
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),

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/LINGYUN.Abp.MicroService.AdminService.csproj

@ -55,6 +55,7 @@
<ProjectReference Include="..\..\framework\mvc\LINGYUN.Abp.AspNetCore.Mvc.Wrapper\LINGYUN.Abp.AspNetCore.Mvc.Wrapper.csproj" />
<ProjectReference Include="..\..\framework\security\LINGYUN.Abp.Claims.Mapping\LINGYUN.Abp.Claims.Mapping.csproj" />
<ProjectReference Include="..\..\framework\wx-pusher\LINGYUN.Abp.WxPusher.SettingManagement\LINGYUN.Abp.WxPusher.SettingManagement.csproj" />
<ProjectReference Include="..\..\modules\blob-management\LINGYUN.Abp.BlobManagement.SettingManagement\LINGYUN.Abp.BlobManagement.SettingManagement.csproj" />
</ItemGroup>
<ItemGroup>

258
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<AbpLocalizationOptions> 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<string>(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<AbpSettingManagementResource>();
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<AbpSettingManagementResource>(name);
}
}

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/appsettings.Development.json

@ -27,6 +27,7 @@
"CollectorCleaningInterval": 3600000
},
"PostgreSql": {
"Schema": "admin",
"TableNamePrefix": "admin",
"ConnectionString": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
},

30
aspnet-core/aspire/LINGYUN.Abp.MicroService.ApiGateway/yarp.json

@ -143,6 +143,21 @@
}
]
},
"gdpr-route": {
"ClusterId": "identity-service-cluster",
"Match": {
"Path": "/api/gdpr/{**everything}"
},
"Transforms": [
{
"HeaderPrefix": "X-Forwarded-",
"X-Forwarded": "Append"
},
{
"ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat"
}
]
},
"identity-server-route": {
"ClusterId": "identity-service-cluster",
"Match": {
@ -293,6 +308,21 @@
}
]
},
"setting-management-v2-route": {
"ClusterId": "admin-service-cluster",
"Match": {
"Path": "/api/v2/setting-management/{**everything}"
},
"Transforms": [
{
"HeaderPrefix": "X-Forwarded-",
"X-Forwarded": "Append"
},
{
"ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat"
}
]
},
"localization-management-route": {
"ClusterId": "localization-service-cluster",
"Match": {

19
aspnet-core/aspire/LINGYUN.Abp.MicroService.AppHost/AppHost.cs

@ -5,7 +5,8 @@ var builder = DistributedApplication.CreateBuilder(args);
// Redis
var redis = builder.AddRedis("redis",
password: builder.AddParameter("redis-password", "123456", secret: true))
.WithContainerName("redis")
.WithContainerName("redis-aspire")
.WithImageTag("8.0.2")
.WithDataVolume("redis-dev");
if (builder.Environment.IsDevelopment())
@ -16,8 +17,9 @@ if (builder.Environment.IsDevelopment())
}
// Elasticsearch
var elasticsearch = builder.AddElasticsearch("elasticsearch")
.WithContainerName("elasticsearch")
var elasticsearch = builder.AddElasticsearch("elasticsearch",
password: builder.AddParameter("elasticsearch-password", "123456", secret: true))
.WithContainerName("elasticsearch-aspire")
.WithImageTag("8.17.3")
.WithDataVolume("elasticsearch-dev")
.WithEnvironment("ES_JAVA_OPTS", "-Xms2g -Xmx2g")
@ -26,15 +28,17 @@ var elasticsearch = builder.AddElasticsearch("elasticsearch")
// Kibana
builder.AddContainer("kibana", "kibana", "8.17.3")
.WithContainerName("kibana-aspire")
.WithReference(elasticsearch)
.WithEndpoint(5601, 5601)
.WaitFor(elasticsearch);
// Postgres
var postgres = builder.AddPostgres("postgres")
.WithPassword(builder.AddParameter("postgres-pwd", "123456", secret: true))
var postgres = builder.AddPostgres("postgres",
userName: builder.AddParameter("postgres-username", "postgres", secret: true),
password: builder.AddParameter("postgres-pwd", "123456", secret: true))
.WithImage("postgres", "17-alpine")
.WithContainerName("postgres")
.WithContainerName("postgres-aspire")
.WithDataVolume("postgres-dev");
var abpDb = postgres.AddDatabase("abp");
@ -43,7 +47,8 @@ var abpDb = postgres.AddDatabase("abp");
var rabbitmq = builder.AddRabbitMQ("rabbitmq",
userName: builder.AddParameter("rabbitmq-username", "admin", secret: true),
password: builder.AddParameter("rabbitmq-password", "123456", secret: true))
.WithContainerName("rabbitmq")
.WithContainerName("rabbitmq-aspire")
.WithImageTag("3.13.1")
.WithDataVolume("rabbitmq-dev")
.WithManagementPlugin();

3
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();
}
}

8
aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/DataSeeds/OpenIddictDataSeeder.cs

@ -478,7 +478,9 @@ public class OpenIddictDataSeeder : OpenIddictDataSeedContributorBase, ITransien
[OpenIddictConstants.GrantTypes.AuthorizationCode,
OpenIddictConstants.GrantTypes.Implicit,
OpenIddictConstants.GrantTypes.Password,
OpenIddictConstants.GrantTypes.RefreshToken],
OpenIddictConstants.GrantTypes.RefreshToken,
// TODO: 引用项目?
"link_user"],
[OpenIddictConstants.Scopes.OpenId,
OpenIddictConstants.Scopes.Email,
OpenIddictConstants.Scopes.Roles,
@ -540,7 +542,9 @@ public class OpenIddictDataSeeder : OpenIddictDataSeedContributorBase, ITransien
"Abp OAuth Client",
null,
[OpenIddictConstants.GrantTypes.AuthorizationCode,
OpenIddictConstants.GrantTypes.RefreshToken],
OpenIddictConstants.GrantTypes.RefreshToken,
// TODO: 引用项目?
"link_user"],
[OpenIddictConstants.Scopes.OpenId,
OpenIddictConstants.Scopes.Email,
OpenIddictConstants.Scopes.Roles,

1403
aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer.EntityFrameworkCore/Migrations/20260530060327_Add-Identity-User-Inactive.Designer.cs

File diff suppressed because it is too large

48
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
{
/// <inheritdoc />
public partial class AddIdentityUserInactive : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpUserInactives",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
LastSignInTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
LastNotificationTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
Status = table.Column<int>(type: "integer", nullable: false),
DeactivatedTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
CreatorId = table.Column<Guid>(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" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpUserInactives");
}
}
}

42
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<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<DateTimeOffset?>("DeactivatedTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset?>("LastNotificationTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset>("LastSignInTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId");
b.ToTable("AbpUserInactives", (string)null);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b =>
{
b.Property<Guid>("Id")

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer/appsettings.Development.json

@ -58,6 +58,7 @@
"CollectorCleaningInterval": 3600000
},
"PostgreSql": {
"Schema": "auth",
"TableNamePrefix": "auth",
"ConnectionString": "Host=localhost;Database=abp;Username=postgres;Password=123456"
},

8
aspnet-core/aspire/LINGYUN.Abp.MicroService.AuthServer/package.json

@ -1,9 +1,9 @@
{
"version": "10.2.0",
"name": "my-app-authserver",
"version": "10.4.0",
"name": "aspire-authserver",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.leptonxlite": "5.2.0",
"@abp/qrcode": "10.2.0"
"@abp/aspnetcore.mvc.ui.theme.leptonxlite": "5.4.0",
"@abp/qrcode": "10.4.0"
}
}

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.IdentityService/appsettings.Development.json

@ -47,6 +47,7 @@
"CollectorCleaningInterval": 3600000
},
"PostgreSql": {
"Schema": "ida",
"TableNamePrefix": "ida",
"ConnectionString": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
},

8
aspnet-core/aspire/LINGYUN.Abp.MicroService.LocalizationService/LocalizationServiceModule.Configure.cs

@ -250,6 +250,14 @@ public partial class LocalizationServiceModule
});
}
private void PreConfigureLocalization()
{
Configure<AbpLocalizationManagementOptions>(options =>
{
options.IsDynamicLocalizationInitializerHost = true;
});
}
private void ConfigureLocalization()
{
// 默认支持的本地化语言类型

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.LocalizationService/LocalizationServiceModule.cs

@ -70,6 +70,7 @@ public partial class LocalizationServiceModule : AbpModule
PreConfigureWrapper();
PreConfigureFeature();
PreForwardedHeaders();
PreConfigureLocalization();
PreConfigureApp(configuration);
PreConfigureCAP(configuration);
}

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.LocalizationService/appsettings.Development.json

@ -27,6 +27,7 @@
"CollectorCleaningInterval": 3600000
},
"PostgreSql": {
"Schema": "lta",
"TableNamePrefix": "lta",
"ConnectionString": "Host=127.0.0.1;Database=abp;Username=postgres;Password=123456"
},

120
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/DataSeeds/NotificationDataSeeder.cs

@ -0,0 +1,120 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;
namespace LINGYUN.Abp.MicroService.MessageService.DataSeeds;
public class NotificationDataSeeder : ITransientDependency
{
public ILogger<NotificationDataSeeder> Logger { protected get; set; }
protected INotificationSender NotificationSender { get; }
protected INotificationSubscriptionManager NotificationSubscriptionManager { get; }
public NotificationDataSeeder(
INotificationSender notificationSender,
INotificationSubscriptionManager notificationSubscriptionManager)
{
NotificationSender = notificationSender;
NotificationSubscriptionManager = notificationSubscriptionManager;
Logger = NullLogger<NotificationDataSeeder>.Instance;
}
public virtual async Task SeedAsync(DataSeedContext context)
{
await SubscribeDefaultNotifierAsync(context);
await SeedWelcomeNotifierAsync(context);
}
public async virtual Task SubscribeDefaultNotifierAsync(DataSeedContext context)
{
if (!context.Properties.TryGetValue(MessageServiceDataSeedConsts.AdminUserIdPropertyName, out var userIdString) ||
!Guid.TryParse(userIdString?.ToString(), out var adminUserId))
{
return;
}
var adminUserName = context.Properties.GetOrDefault(MessageServiceDataSeedConsts.AdminUserNamePropertyName)?.ToString()
?? MessageServiceDataSeedConsts.AdminUserNameDefaultValue;
var userIdentifer = new UserIdentifier(adminUserId, adminUserName);
// 订阅内置通知
await NotificationSubscriptionManager
.SubscribeAsync(
context.TenantId,
userIdentifer,
DefaultNotifications.SystemNotice);
await NotificationSubscriptionManager
.SubscribeAsync(
context.TenantId,
userIdentifer,
DefaultNotifications.OnsideNotice);
await NotificationSubscriptionManager
.SubscribeAsync(
context.TenantId,
userIdentifer,
DefaultNotifications.ActivityNotice);
// 订阅用户欢迎消息
await NotificationSubscriptionManager
.SubscribeAsync(
context.TenantId,
userIdentifer,
UserNotificationNames.WelcomeToApplication);
}
public async virtual Task SeedWelcomeNotifierAsync(DataSeedContext context)
{
try
{
if (!context.TenantId.HasValue)
{
return;
}
if (!context.Properties.TryGetValue(MessageServiceDataSeedConsts.AdminUserIdPropertyName, out var userIdString) ||
!Guid.TryParse(userIdString?.ToString(), out var adminUserId))
{
return;
}
var adminEmailAddress = context.Properties.GetOrDefault(MessageServiceDataSeedConsts.AdminEmailPropertyName)?.ToString()
?? MessageServiceDataSeedConsts.AdminEmailDefaultValue;
var adminUserName = context.Properties.GetOrDefault(MessageServiceDataSeedConsts.AdminUserNamePropertyName)?.ToString()
?? MessageServiceDataSeedConsts.AdminUserNameDefaultValue;
var tenantAdminUserIdentifier = new UserIdentifier(adminUserId, adminEmailAddress);
// 租户管理员订阅事件
await NotificationSubscriptionManager
.SubscribeAsync(
context.TenantId,
tenantAdminUserIdentifier,
TenantNotificationNames.NewTenantRegistered);
Logger.LogInformation("publish new tenant notification..");
await NotificationSender.SendNofiterAsync(
TenantNotificationNames.NewTenantRegistered,
new NotificationTemplate(
TenantNotificationNames.NewTenantRegistered,
formUser: adminEmailAddress,
data: new Dictionary<string, object>
{
{ "name", adminUserName },
{ "email", adminEmailAddress },
{ "id", context.TenantId },
}),
tenantAdminUserIdentifier,
context.TenantId,
NotificationSeverity.Success);
Logger.LogInformation("tenant administrator subscribes to new tenant events..");
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Failed to send the tenant initialization notification.");
}
}
}

10
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDataSeedConsts.cs

@ -0,0 +1,10 @@
namespace LINGYUN.Abp.MicroService.MessageService;
public static class MessageServiceDataSeedConsts
{
public const string AdminUserIdPropertyName = "AdminUserId";
public const string AdminEmailPropertyName = "AdminEmail";
public const string AdminEmailDefaultValue = "admin@abp.io";
public const string AdminUserNamePropertyName = "AdminUserName";
public const string AdminUserNameDefaultValue = "admin";
}

33
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDataSeeder.cs

@ -0,0 +1,33 @@
using LINGYUN.Abp.MicroService.MessageService.DataSeeds;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.MicroService.MessageService;
public class MessageServiceDataSeeder : ITransientDependency
{
protected NotificationDataSeeder NotificationDataSeeder { get; }
protected ICurrentTenant CurrentTenant { get; }
public MessageServiceDataSeeder(
ICurrentTenant currentTenant,
NotificationDataSeeder notificationDataSeeder)
{
CurrentTenant = currentTenant;
NotificationDataSeeder = notificationDataSeeder;
}
public async virtual Task SeedAsync(DataSeedContext context)
{
using (CurrentTenant.Change(context.TenantId))
{
await SeedNotificationAsync(context);
}
}
private async Task SeedNotificationAsync(DataSeedContext context)
{
await NotificationDataSeeder.SeedAsync(context);
}
}

64
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDbMigrationEventHandler.cs

@ -1,7 +1,4 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DistributedLocking;
@ -13,8 +10,7 @@ using Volo.Abp.Uow;
namespace LINGYUN.Abp.MicroService.MessageService;
public class MessageServiceDbMigrationEventHandler : EfCoreDatabaseMigrationEventHandlerBase<MessageServiceMigrationsDbContext>
{
protected INotificationSender NotificationSender { get; }
protected INotificationSubscriptionManager NotificationSubscriptionManager { get; }
protected MessageServiceDataSeeder MessageServiceDataSeeder { get; }
public MessageServiceDbMigrationEventHandler(
ICurrentTenant currentTenant,
@ -23,65 +19,27 @@ public class MessageServiceDbMigrationEventHandler : EfCoreDatabaseMigrationEven
IAbpDistributedLock abpDistributedLock,
IDistributedEventBus distributedEventBus,
ILoggerFactory loggerFactory,
INotificationSender notificationSender,
INotificationSubscriptionManager notificationSubscriptionManager)
MessageServiceDataSeeder messageServiceDataSeeder)
: base(
ConnectionStringNameAttribute.GetConnStringName<MessageServiceMigrationsDbContext>(),
currentTenant, unitOfWorkManager, tenantStore, abpDistributedLock, distributedEventBus, loggerFactory)
{
NotificationSender = notificationSender;
NotificationSubscriptionManager = notificationSubscriptionManager;
MessageServiceDataSeeder = messageServiceDataSeeder;
}
protected async override Task AfterTenantCreated(TenantCreatedEto eventData, bool schemaMigrated)
{
using (CurrentTenant.Change(eventData.Id))
{
await SendNotificationAsync(eventData);
}
}
protected async virtual Task SendNotificationAsync(TenantCreatedEto eventData)
{
try
{
if (!eventData.Properties.TryGetValue("AdminUserId", out var userIdString) ||
!Guid.TryParse(userIdString, out var adminUserId))
var context = new DataSeedContext(eventData.Id);
if (eventData.Properties != null)
{
return;
foreach (var prop in eventData.Properties)
{
context.WithProperty(prop.Key, prop.Value);
}
}
var adminEmailAddress = eventData.Properties.GetOrDefault("AdminEmail") ?? "admin@abp.io";
var tenantAdminUserIdentifier = new UserIdentifier(adminUserId, adminEmailAddress);
// 租户管理员订阅事件
await NotificationSubscriptionManager
.SubscribeAsync(
eventData.Id,
tenantAdminUserIdentifier,
TenantNotificationNames.NewTenantRegistered);
Logger.LogInformation("publish new tenant notification..");
await NotificationSender.SendNofiterAsync(
TenantNotificationNames.NewTenantRegistered,
new NotificationTemplate(
TenantNotificationNames.NewTenantRegistered,
formUser: adminEmailAddress,
data: new Dictionary<string, object>
{
{ "name", eventData.Name },
{ "email", adminEmailAddress },
{ "id", eventData.Id },
}),
tenantAdminUserIdentifier,
eventData.Id,
NotificationSeverity.Success);
Logger.LogInformation("tenant administrator subscribes to new tenant events..");
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Failed to send the tenant initialization notification.");
await MessageServiceDataSeeder.SeedAsync(context);
}
}
}

10
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceDbMigrationService.cs

@ -1,6 +1,7 @@
using LINGYUN.Abp.Data.DbMigrator;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DistributedLocking;
@ -11,7 +12,9 @@ using Volo.Abp.Uow;
namespace LINGYUN.Abp.MicroService.MessageService;
public class MessageServiceDbMigrationService : EfCoreRuntimeDbMigratorBase<MessageServiceMigrationsDbContext>, ITransientDependency
{
protected MessageServiceDataSeeder DataSeeder { get; }
public MessageServiceDbMigrationService(
MessageServiceDataSeeder dataSeeder,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IServiceProvider serviceProvider,
@ -22,5 +25,12 @@ public class MessageServiceDbMigrationService : EfCoreRuntimeDbMigratorBase<Mess
ConnectionStringNameAttribute.GetConnStringName<MessageServiceMigrationsDbContext>(),
unitOfWorkManager, serviceProvider, currentTenant, abpDistributedLock, distributedEventBus, loggerFactory)
{
DataSeeder = dataSeeder;
}
protected async override Task SeedAsync()
{
// DbMigrator迁移数据种子
await DataSeeder.SeedAsync(new DataSeedContext());
}
}

13
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
/// </summary>
protected ICurrentTenant CurrentTenant { get; }
/// <summary>
/// Reference to <see cref="ITenantConfigurationCache"/>.
/// Reference to <see cref="ITenantStore"/>.
/// </summary>
protected ITenantConfigurationCache TenantConfigurationCache { get; }
protected ITenantStore TenantStore { get; }
/// <summary>
/// Reference to <see cref="IJsonSerializer"/>.
/// </summary>
@ -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)
{

70
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/TenantSynchronizer.cs

@ -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<EntityCreatedEto<TenantEto>>,
IDistributedEventHandler<EntityUpdatedEto<TenantEto>>,
IDistributedEventHandler<EntityDeletedEto<TenantEto>>,
IDistributedEventHandler<TenantConnectionStringUpdatedEto>,
ITransientDependency
{
protected ILogger<TenantSynchronizer> 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<TenantSynchronizer> logger)
{
Logger = logger;
CurrentTenant = currentTenant;
DbSchemaMigrator = dbSchemaMigrator;
UnitOfWorkManager = unitOfWorkManager;
TenantConfigurationCache = tenantConfigurationCache;
NotificationSender = notificationSender;
NotificationSubscriptionManager = notificationSubscriptionManager;
}
public async virtual Task HandleEventAsync(EntityCreatedEto<TenantEto> eventData)
{
await TenantConfigurationCache.RefreshAsync();
}
public async virtual Task HandleEventAsync(EntityUpdatedEto<TenantEto> eventData)
{
await TenantConfigurationCache.RefreshAsync();
}
public async virtual Task HandleEventAsync(EntityDeletedEto<TenantEto> eventData)
{
await TenantConfigurationCache.RefreshAsync();
}
public async virtual Task HandleEventAsync(TenantConnectionStringUpdatedEto eventData)
{
await TenantConfigurationCache.RefreshAsync();
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save