Browse Source

Merge pull request #1445 from colinin/notifier-send-records

feat: Add notification sending records
pull/1455/head
yx lin 4 days ago
committed by GitHub
parent
commit
438ed31e79
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      Directory.Packages.props
  2. 68
      aspnet-core/LINGYUN.MicroService.SingleProject.sln
  3. 1
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceMigrationsEntityFrameworkCoreModule.cs
  4. 812
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.Designer.cs
  5. 49
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.cs
  6. 55
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/MessageServiceMigrationsDbContextModelSnapshot.cs
  7. 69
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/BackgroundJobs/NotificationPublishJob.cs
  8. 59
      aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs
  9. 5696
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.Designer.cs
  10. 150
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.cs
  11. 5749
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260324062229_Add-Notification-Send-Record.Designer.cs
  12. 49
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260324062229_Add-Notification-Send-Record.cs
  13. 332
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/SingleMigrationsDbContextModelSnapshot.cs
  14. 5701
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260319053918_Add-AI-Management-Module.Designer.cs
  15. 150
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260319053918_Add-AI-Management-Module.cs
  16. 5754
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260324062303_Add-Notification-Send-Record.Designer.cs
  17. 48
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260324062303_Add-Notification-Send-Record.cs
  18. 332
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/SingleMigrationsDbContextModelSnapshot.cs
  19. 1
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj
  20. 22
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs
  21. 2
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs
  22. 2
      aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageStoreCache.cs
  23. 11
      aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin5/LINGYUN/Abp/UI/Navigation/VueVbenAdmin5/AbpUINavigationVueVbenAdmin5NavigationDefinitionProvider.cs
  24. 14
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Dto/NotificationSendRecordDto.cs
  25. 16
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Dto/NotificationSendRecordGetPagedListInput.cs
  26. 5
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Dto/UserNotificationGetByPagedDto.cs
  27. 13
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/INotificationSendRecordAppService.cs
  28. 6
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Permissions/NotificationsPermissions.cs
  29. 5
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Permissions/NotificationsPermissionsDefinitionProvider.cs
  30. 26
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/AbpNotificationsApplicationMappers.cs
  31. 38
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/MyNotificationAppService.cs
  32. 107
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/NotificationSendRecordAppService.cs
  33. 35
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationPublishContext.cs
  34. 49
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationSendInfo.cs
  35. 23
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationSendState.cs
  36. 6
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/AbpNotificationsDomainSharedModule.cs
  37. 17
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/Localization/DomainShared/en.json
  38. 17
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/Localization/DomainShared/zh-Hans.json
  39. 6
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/NotificationSendRecordConsts.cs
  40. 20
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/INotificationSendRecordRepository.cs
  41. 14
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/IUserNotificationRepository.cs
  42. 48
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/NotificationSendRecord.cs
  43. 14
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/NotificationSendRecordInfo.cs
  44. 33
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/NotificationStore.cs
  45. 15
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Emailing/LINGYUN/Abp/Notifications/Emailing/EmailingNotificationPublishProvider.cs
  46. 2
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/AbpNotificationsEntityFrameworkCoreModule.cs
  47. 99
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/EfCoreNotificationSendRecordRepository.cs
  48. 81
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/EfCoreUserNotificationRepository.cs
  49. 4
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/INotificationsDbContext.cs
  50. 4
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/NotificationsDbContext.cs
  51. 99
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/NotificationsDbContextModelCreatingExtensions.cs
  52. 45
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.HttpApi/LINGYUN/Abp/Notifications/NotificationSendRecordController.cs
  53. 13
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.PushPlus/LINGYUN/Abp/Notifications/PushPlus/PushPlusNotificationPublishProvider.cs
  54. 23
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs
  55. 13
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Sms/LINGYUN/Abp/Notifications/Sms/SmsNotificationPublishProvider.cs
  56. 94
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.MiniProgram/LINGYUN/Abp/Notifications/WeChat/MiniProgram/WeChatMiniProgramNotificationPublishProvider.cs
  57. 30
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs
  58. 14
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WxPusher/LINGYUN/Abp/Notifications/WxPusher/WxPusherNotificationPublishProvider.cs
  59. 14
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProvider.cs
  60. 4
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs
  61. 27
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs
  62. 7
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NullNotificationStore.cs
  63. 68
      aspnet-core/services/LY.MicroService.Applications.Single/BackgroundJobs/NotificationPublishJob.cs
  64. 66
      aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs
  65. 4
      aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
  66. 13
      aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
  67. 7
      aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
  68. 69
      aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/BackgroundJobs/NotificationPublishJob.cs
  69. 59
      aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs
  70. 25
      aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.PostgreSql.json

1
Directory.Packages.props

@ -255,6 +255,7 @@
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageVersion Include="Serilog.Enrichers.Assembly" Version="2.0.0" />
<PackageVersion Include="Serilog.Enrichers.AssemblyName" Version="2.0.0" />
<PackageVersion Include="Serilog.Enrichers.Process" Version="3.0.0" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />

68
aspnet-core/LINGYUN.MicroService.SingleProject.sln

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36616.10 d17.14
VisualStudioVersion = 17.14.36616.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{0B58AA48-665A-443F-A6A8-751FB9629DAF}"
EndProject
@ -700,6 +700,26 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Work.OA"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.PostgresSqlInstaller", "modules\task-management\LINGYUN.Abp.Quartz.PostgresSqlInstaller\LINGYUN.Abp.Quartz.PostgresSqlInstaller.csproj", "{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ai", "ai", "{E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AI.Core", "modules\ai\LINGYUN.Abp.AI.Core\LINGYUN.Abp.AI.Core.csproj", "{72083C13-32E8-1122-7761-CE7C0B64AABA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AI.Agent", "modules\ai\LINGYUN.Abp.AI.Agent\LINGYUN.Abp.AI.Agent.csproj", "{F80E583B-93F3-C1E6-A83D-AC83132DBC5F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Domain.Shared", "modules\ai\LINGYUN.Abp.AIManagement.Domain.Shared\LINGYUN.Abp.AIManagement.Domain.Shared.csproj", "{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Domain", "modules\ai\LINGYUN.Abp.AIManagement.Domain\LINGYUN.Abp.AIManagement.Domain.csproj", "{7D372713-5117-82F2-7591-C0AE09BA04CF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Application.Contracts", "modules\ai\LINGYUN.Abp.AIManagement.Application.Contracts\LINGYUN.Abp.AIManagement.Application.Contracts.csproj", "{479D24D3-D01D-6655-87E8-5A236B3BA371}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Application", "modules\ai\LINGYUN.Abp.AIManagement.Application\LINGYUN.Abp.AIManagement.Application.csproj", "{62A90887-34B9-1BDE-8851-9CC926AEBBBE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.EntityFrameworkCore", "modules\ai\LINGYUN.Abp.AIManagement.EntityFrameworkCore\LINGYUN.Abp.AIManagement.EntityFrameworkCore.csproj", "{5AFC464A-9B1F-7415-2D2E-320D567ED818}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.HttpApi", "modules\ai\LINGYUN.Abp.AIManagement.HttpApi\LINGYUN.Abp.AIManagement.HttpApi.csproj", "{3B618981-F1CB-9AEC-E90B-4B05B982C1FC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.HttpApi.Client", "modules\ai\LINGYUN.Abp.AIManagement.HttpApi.Client\LINGYUN.Abp.AIManagement.HttpApi.Client.csproj", "{44957812-548A-D14C-6C92-F9902DADDCDA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1866,6 +1886,42 @@ Global
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}.Release|Any CPU.Build.0 = Release|Any CPU
{72083C13-32E8-1122-7761-CE7C0B64AABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72083C13-32E8-1122-7761-CE7C0B64AABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72083C13-32E8-1122-7761-CE7C0B64AABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72083C13-32E8-1122-7761-CE7C0B64AABA}.Release|Any CPU.Build.0 = Release|Any CPU
{F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Release|Any CPU.Build.0 = Release|Any CPU
{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Release|Any CPU.Build.0 = Release|Any CPU
{7D372713-5117-82F2-7591-C0AE09BA04CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D372713-5117-82F2-7591-C0AE09BA04CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D372713-5117-82F2-7591-C0AE09BA04CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D372713-5117-82F2-7591-C0AE09BA04CF}.Release|Any CPU.Build.0 = Release|Any CPU
{479D24D3-D01D-6655-87E8-5A236B3BA371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{479D24D3-D01D-6655-87E8-5A236B3BA371}.Debug|Any CPU.Build.0 = Debug|Any CPU
{479D24D3-D01D-6655-87E8-5A236B3BA371}.Release|Any CPU.ActiveCfg = Release|Any CPU
{479D24D3-D01D-6655-87E8-5A236B3BA371}.Release|Any CPU.Build.0 = Release|Any CPU
{62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Release|Any CPU.Build.0 = Release|Any CPU
{5AFC464A-9B1F-7415-2D2E-320D567ED818}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5AFC464A-9B1F-7415-2D2E-320D567ED818}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5AFC464A-9B1F-7415-2D2E-320D567ED818}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5AFC464A-9B1F-7415-2D2E-320D567ED818}.Release|Any CPU.Build.0 = Release|Any CPU
{3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Release|Any CPU.Build.0 = Release|Any CPU
{44957812-548A-D14C-6C92-F9902DADDCDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44957812-548A-D14C-6C92-F9902DADDCDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44957812-548A-D14C-6C92-F9902DADDCDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44957812-548A-D14C-6C92-F9902DADDCDA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2207,6 +2263,16 @@ Global
{C996D147-5B81-49D9-949B-F3BC185B2CD4} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
{AB207B2A-C8E7-977D-98E6-66527CBB2B7F} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2} = {91EE5D5B-B6DF-43F1-BC09-1A982719A34B}
{E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC} = {0B58AA48-665A-443F-A6A8-751FB9629DAF}
{72083C13-32E8-1122-7761-CE7C0B64AABA} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{F80E583B-93F3-C1E6-A83D-AC83132DBC5F} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{7D372713-5117-82F2-7591-C0AE09BA04CF} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{479D24D3-D01D-6655-87E8-5A236B3BA371} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{62A90887-34B9-1BDE-8851-9CC926AEBBBE} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{5AFC464A-9B1F-7415-2D2E-320D567ED818} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{3B618981-F1CB-9AEC-E90B-4B05B982C1FC} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
{44957812-548A-D14C-6C92-F9902DADDCDA} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}

1
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceMigrationsEntityFrameworkCoreModule.cs

@ -4,6 +4,7 @@ using LINGYUN.Abp.Notifications.EntityFrameworkCore;
using LINGYUN.Abp.Quartz.PostgresSqlInstaller;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
using LINGYUN.Abp.TextTemplating.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.EntityFrameworkCore;

812
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.Designer.cs

@ -0,0 +1,812 @@
// <auto-generated />
using System;
using LINGYUN.Abp.MicroService.MessageService;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Volo.Abp.EntityFrameworkCore;
#nullable disable
namespace LINGYUN.Abp.MicroService.MessageService.Migrations
{
[DbContext(typeof(MessageServiceMigrationsDbContext))]
[Migration("20260320092811_Add-Notification-Send-Record")]
partial class AddNotificationSendRecord
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatCard", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("Age")
.HasColumnType("integer");
b.Property<string>("AvatarUrl")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<DateTime?>("Birthday")
.HasColumnType("timestamp with time zone");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("LastOnlineTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("NickName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<int>("Sex")
.HasColumnType("integer");
b.Property<string>("Sign")
.HasMaxLength(30)
.HasColumnType("character varying(30)");
b.Property<int>("State")
.HasColumnType("integer");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId");
b.ToTable("AppUserChatCards", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatFriend", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<bool>("Black")
.HasColumnType("boolean");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<bool>("DontDisturb")
.HasColumnType("boolean");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<Guid>("FrientId")
.HasColumnType("uuid");
b.Property<bool>("IsStatic")
.HasColumnType("boolean");
b.Property<string>("RemarkName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("SpecialFocus")
.HasColumnType("boolean");
b.Property<byte>("Status")
.HasColumnType("smallint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId", "FrientId");
b.ToTable("AppUserChatFriends", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatSetting", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<bool>("AllowAddFriend")
.HasColumnType("boolean");
b.Property<bool>("AllowAnonymous")
.HasColumnType("boolean");
b.Property<bool>("AllowReceiveMessage")
.HasColumnType("boolean");
b.Property<bool>("AllowSendMessage")
.HasColumnType("boolean");
b.Property<bool>("RequireAddFriendValition")
.HasColumnType("boolean");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId");
b.ToTable("AppUserChatSettings", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserMessage", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1048576)
.HasColumnType("character varying(1048576)");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<long>("MessageId")
.HasColumnType("bigint");
b.Property<Guid>("ReceiveUserId")
.HasColumnType("uuid");
b.Property<string>("SendUserName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<int>("Source")
.HasColumnType("integer");
b.Property<short>("State")
.HasColumnType("smallint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<int>("Type")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("TenantId", "ReceiveUserId");
b.ToTable("AppUserMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.ChatGroup", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Address")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<Guid>("AdminUserId")
.HasColumnType("uuid");
b.Property<bool>("AllowAnonymous")
.HasColumnType("boolean");
b.Property<bool>("AllowSendMessage")
.HasColumnType("boolean");
b.Property<string>("AvatarUrl")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<long>("GroupId")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<int>("MaxUserCount")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Notice")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Tag")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("TenantId", "Name");
b.ToTable("AppChatGroups", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupChatBlack", b =>
{
b.Property<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<long>("GroupId")
.HasColumnType("bigint");
b.Property<Guid>("ShieldUserId")
.HasColumnType("uuid");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("TenantId", "GroupId");
b.ToTable("AppGroupChatBlacks", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupMessage", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1048576)
.HasColumnType("character varying(1048576)");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<long>("GroupId")
.HasColumnType("bigint");
b.Property<long>("MessageId")
.HasColumnType("bigint");
b.Property<string>("SendUserName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<int>("Source")
.HasColumnType("integer");
b.Property<short>("State")
.HasColumnType("smallint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<int>("Type")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("TenantId", "GroupId");
b.ToTable("AppGroupMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserChatGroup", b =>
{
b.Property<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<long>("GroupId")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TenantId", "GroupId", "UserId");
b.ToTable("AppUserChatGroups", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserGroupCard", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsAdmin")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("NickName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<DateTime?>("SilenceEnd")
.HasColumnType("timestamp with time zone");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId");
b.ToTable("AppUserGroupCards", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.Notification", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<int>("ContentType")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0);
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<DateTime?>("ExpirationTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("ExtraProperties")
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<long>("NotificationId")
.HasColumnType("bigint");
b.Property<string>("NotificationName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("NotificationTypeName")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<short>("Severity")
.HasColumnType("smallint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<int>("Type")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("TenantId", "NotificationName");
b.ToTable("AppNotifications", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionGroupRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<bool>("AllowSubscriptionToClients")
.HasColumnType("boolean");
b.Property<string>("Description")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("DisplayName")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("ExtraProperties")
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.HasKey("Id");
b.ToTable("AppNotificationDefinitionGroups", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<bool>("AllowSubscriptionToClients")
.HasColumnType("boolean");
b.Property<int>("ContentType")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(0);
b.Property<string>("Description")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("DisplayName")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("ExtraProperties")
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<string>("GroupName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<int>("NotificationLifetime")
.HasColumnType("integer");
b.Property<int>("NotificationType")
.HasColumnType("integer");
b.Property<string>("Providers")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Template")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.HasKey("Id");
b.ToTable("AppNotificationDefinitions", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long>("NotificationId")
.HasColumnType("bigint");
b.Property<string>("NotificationName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Reason")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<DateTime>("SendTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("State")
.HasColumnType("integer");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("UserName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasDefaultValue("/");
b.HasKey("Id");
b.HasIndex("TenantId", "NotificationName")
.HasDatabaseName("IX_Tenant_Send_Notification_Name");
b.ToTable("AppNotificationSendRecords", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long>("NotificationId")
.HasColumnType("bigint");
b.Property<int>("ReadStatus")
.HasColumnType("integer");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId", "NotificationId")
.HasDatabaseName("IX_Tenant_User_Notification_Id");
b.ToTable("AppUserNotifications", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.UserSubscribe", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnName("CreationTime");
b.Property<string>("NotificationName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("UserName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasDefaultValue("/");
b.HasKey("Id");
b.HasIndex("TenantId", "UserId", "NotificationName")
.IsUnique()
.HasDatabaseName("IX_Tenant_User_Notification_Name");
b.ToTable("AppUserSubscribes", (string)null);
});
#pragma warning restore 612, 618
}
}
}

49
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.cs

@ -0,0 +1,49 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace LINGYUN.Abp.MicroService.MessageService.Migrations
{
/// <inheritdoc />
public partial class AddNotificationSendRecord : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppNotificationSendRecords",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Provider = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
SendTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
UserName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, defaultValue: "/"),
NotificationId = table.Column<long>(type: "bigint", nullable: false),
NotificationName = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
State = table.Column<int>(type: "integer", nullable: false),
Reason = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppNotificationSendRecords", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Tenant_Send_Notification_Name",
table: "AppNotificationSendRecords",
columns: new[] { "TenantId", "NotificationName" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppNotificationSendRecords");
}
}
}

55
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/MessageServiceMigrationsDbContextModelSnapshot.cs

@ -19,7 +19,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@ -682,6 +682,59 @@ namespace LINGYUN.Abp.MicroService.MessageService.Migrations
b.ToTable("AppNotificationDefinitions", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long>("NotificationId")
.HasColumnType("bigint");
b.Property<string>("NotificationName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Reason")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<DateTime>("SendTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("State")
.HasColumnType("integer");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("UserName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasDefaultValue("/");
b.HasKey("Id");
b.HasIndex("TenantId", "NotificationName")
.HasDatabaseName("IX_Tenant_Send_Notification_Name");
b.ToTable("AppNotificationSendRecords", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b =>
{
b.Property<long>("Id")

69
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/BackgroundJobs/NotificationPublishJob.cs

@ -1,25 +1,34 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
namespace LINGYUN.Abp.MicroService.MessageService.BackgroundJobs;
public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobArgs>, ITransientDependency
{
protected IClock Clock { get; }
protected AbpNotificationsPublishOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected INotificationStore NotificationStore { get; }
protected INotificationDataSerializer NotificationDataSerializer { get; }
public NotificationPublishJob(
IClock clock,
IOptions<AbpNotificationsPublishOptions> options,
IServiceScopeFactory serviceScopeFactory,
INotificationStore notificationStore,
INotificationDataSerializer notificationDataSerializer)
{
Clock = clock;
Options = options.Value;
ServiceScopeFactory = serviceScopeFactory;
NotificationStore = notificationStore;
NotificationDataSerializer = notificationDataSerializer;
}
@ -33,9 +42,65 @@ public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobA
var store = scope.ServiceProvider.GetRequiredService<INotificationStore>();
var notification = await store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId);
notification.Data = NotificationDataSerializer.Serialize(notification.Data);
await publishProvider.PublishAsync(notification, args.UserIdentifiers);
var sendInfo = OnPublishing(publishProvider, notification, args.UserIdentifiers);
try
{
if (await publishProvider.CanPublishAsync(notification))
{
var context = new NotificationPublishContext(notification, args.UserIdentifiers);
// 发布
await publishProvider.PublishAsync(context);
sendInfo.Sent(context.Exception);
if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
{
sendInfo.Cancel(context.Reason);
}
Logger.LogDebug($"Send notification {notification.Name} with provider {publishProvider.Name} was successful");
}
else
{
sendInfo.Disbaled();
}
await OnPublished(sendInfo);
}
catch (Exception ex)
{
Logger.LogWarning($"Send notification error with provider {publishProvider.Name}");
Logger.LogWarning($"Error message:{ex.Message}");
try
{
sendInfo.Sent(ex);
await OnPublished(sendInfo);
}
catch { }
throw;
}
}
}
}
protected virtual NotificationSendInfo OnPublishing(
INotificationPublishProvider provider,
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
{
return new NotificationSendInfo(
provider.Name,
Clock.Now,
notification,
identifiers);
}
protected async Task OnPublished(NotificationSendInfo sendInfo)
{
await NotificationStore.InsertSendStateAsync(sendInfo);
}
}

59
aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs

@ -19,6 +19,7 @@ using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Settings;
using Volo.Abp.TextTemplating;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
@ -44,6 +45,10 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
/// </summary>
protected AbpNotificationsPublishOptions Options { get; }
/// <summary>
/// Reference to <see cref="IClock"/>.
/// </summary>
protected IClock Clock { get; }
/// <summary>
/// Reference to <see cref="ISettingProvider"/>.
/// </summary>
protected ISettingProvider SettingProvider { get; }
@ -100,6 +105,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
/// Initializes a new instance of the <see cref="NotificationEventHandler"/> class.
/// </summary>
public NotificationEventHandler(
IClock clock,
ICurrentTenant currentTenant,
ISettingProvider settingProvider,
ITenantConfigurationCache tenantConfigurationCache,
@ -115,6 +121,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
INotificationSubscriptionManager notificationSubscriptionManager,
INotificationPublishProviderManager notificationPublishProviderManager)
{
Clock = clock;
Options = options.Value;
TenantConfigurationCache = tenantConfigurationCache;
CurrentTenant = currentTenant;
@ -435,20 +442,40 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
/// </summary>
/// <param name="provider">通知发布者</param>
/// <param name="notificationInfo">通知信息</param>
/// <param name="subscriptionUserIdentifiers">订阅用户列表</param>
/// <param name="subscriptionUsers">订阅用户列表</param>
/// <returns></returns>
protected async Task PublishToSubscriberAsync(
INotificationPublishProvider provider,
NotificationInfo notificationInfo,
IEnumerable<UserIdentifier> subscriptionUsers)
{
var sendInfo = OnPublishing(provider, notificationInfo, subscriptionUsers);
try
{
Logger.LogDebug($"Sending notification with provider {provider.Name}");
// 发布
await provider.PublishAsync(notificationInfo, subscriptionUsers);
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
if (await provider.CanPublishAsync(notificationInfo))
{
var context = new NotificationPublishContext(notificationInfo, subscriptionUsers);
// 发布
await provider.PublishAsync(context);
sendInfo.Sent(context.Exception);
if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
{
sendInfo.Cancel(context.Reason);
}
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
}
else
{
sendInfo.Disbaled();
}
await OnPublished(sendInfo);
}
catch (Exception ex)
{
@ -457,6 +484,13 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
Logger.LogDebug($"Failed to send notification {notificationInfo.Name}. Try to push notification to background job");
// 发送失败的消息进入后台队列
await ProcessingFailedToQueueAsync(provider, notificationInfo, subscriptionUsers);
try
{
sendInfo.Sent(ex);
await OnPublished(sendInfo);
}
catch { }
}
}
/// <summary>
@ -489,5 +523,22 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
Logger.LogWarning("Failed to push to background job, notification will be discarded, error cause: {message}", ex.Message);
}
}
protected virtual NotificationSendInfo OnPublishing(
INotificationPublishProvider provider,
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
{
return new NotificationSendInfo(
provider.Name,
Clock.Now,
notification,
identifiers);
}
protected async Task OnPublished(NotificationSendInfo sendInfo)
{
await NotificationStore.InsertSendStateAsync(sendInfo);
}
}
}

5696
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.Designer.cs

File diff suppressed because it is too large

150
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.cs

@ -0,0 +1,150 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Migrations
{
/// <inheritdoc />
public partial class AddAIManagementModule : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpAIConversations",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Name = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
Workspace = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
ExpiredAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
UpdateAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAIConversations", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAITextChatMessages",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Content = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
ExtraProperties = table.Column<string>(type: "text", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Workspace = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
Role = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: true),
ConversationId = table.Column<Guid>(type: "uuid", nullable: true),
ReplyMessage = table.Column<string>(type: "text", nullable: true),
ReplyAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAITextChatMessages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAITokenUsages",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
MessageId = table.Column<Guid>(type: "uuid", nullable: true),
ConversationId = table.Column<Guid>(type: "uuid", nullable: true),
InputTokenCount = table.Column<long>(type: "bigint", nullable: true),
OutputTokenCount = table.Column<long>(type: "bigint", nullable: true),
TotalTokenCount = table.Column<long>(type: "bigint", nullable: true),
CachedInputTokenCount = table.Column<long>(type: "bigint", nullable: true),
ReasoningTokenCount = table.Column<long>(type: "bigint", nullable: true),
CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAITokenUsages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAIWorkspaceDefinitions",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
Provider = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
ModelName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
DisplayName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
Description = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
ApiKey = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
ApiBaseUrl = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
SystemPrompt = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
Instructions = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
Temperature = table.Column<float>(type: "real", nullable: true),
MaxOutputTokens = table.Column<int>(type: "integer", nullable: true),
FrequencyPenalty = table.Column<float>(type: "real", nullable: true),
PresencePenalty = table.Column<float>(type: "real", nullable: true),
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
StateCheckers = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ExtraProperties = table.Column<string>(type: "text", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
CreatorId = table.Column<Guid>(type: "uuid", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
LastModifierId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAIWorkspaceDefinitions", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_AbpAITextChatMessages_TenantId_ConversationId",
table: "AbpAITextChatMessages",
columns: new[] { "TenantId", "ConversationId" });
migrationBuilder.CreateIndex(
name: "IX_AbpAITokenUsages_TenantId_ConversationId",
table: "AbpAITokenUsages",
columns: new[] { "TenantId", "ConversationId" });
migrationBuilder.CreateIndex(
name: "IX_AbpAIWorkspaceDefinitions_Name",
table: "AbpAIWorkspaceDefinitions",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpAIConversations");
migrationBuilder.DropTable(
name: "AbpAITextChatMessages");
migrationBuilder.DropTable(
name: "AbpAITokenUsages");
migrationBuilder.DropTable(
name: "AbpAIWorkspaceDefinitions");
}
}
}

5749
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260324062229_Add-Notification-Send-Record.Designer.cs

File diff suppressed because it is too large

49
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260324062229_Add-Notification-Send-Record.cs

@ -0,0 +1,49 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Migrations
{
/// <inheritdoc />
public partial class AddNotificationSendRecord : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppNotificationSendRecords",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
TenantId = table.Column<Guid>(type: "uuid", nullable: true),
Provider = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
SendTime = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
UserName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, defaultValue: "/"),
NotificationId = table.Column<long>(type: "bigint", nullable: false),
NotificationName = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
State = table.Column<int>(type: "integer", nullable: false),
Reason = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppNotificationSendRecords", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Tenant_Send_Notification_Name",
table: "AppNotificationSendRecords",
columns: new[] { "TenantId", "NotificationName" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppNotificationSendRecords");
}
}
}

332
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/SingleMigrationsDbContextModelSnapshot.cs

@ -24,6 +24,285 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Mig
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<DateTime>("ExpiredAt")
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<DateTime?>("UpdateAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.ToTable("AbpAIConversations", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("ReplyAt")
.HasColumnType("timestamp without time zone");
b.Property<string>("ReplyMessage")
.HasColumnType("text");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITextChatMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<long?>("CachedInputTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("ConversationId")
.HasColumnType("uuid");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<long?>("InputTokenCount")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MessageId")
.HasColumnType("uuid");
b.Property<long?>("OutputTokenCount")
.HasColumnType("bigint");
b.Property<long?>("ReasoningTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<long?>("TotalTokenCount")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITokenUsages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("ApiBaseUrl")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ApiKey")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("text")
.HasColumnName("ExtraProperties");
b.Property<float?>("FrequencyPenalty")
.HasColumnType("real");
b.Property<string>("Instructions")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<bool>("IsEnabled")
.HasColumnType("boolean");
b.Property<bool>("IsSystem")
.HasColumnType("boolean");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp without time zone")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uuid")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxOutputTokens")
.HasColumnType("integer");
b.Property<string>("ModelName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<float?>("PresencePenalty")
.HasColumnType("real");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("SystemPrompt")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
b.Property<float?>("Temperature")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b =>
{
b.Property<Guid>("Id")
@ -1395,6 +1674,59 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Mig
b.ToTable("AppNotificationDefinitions", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<long>("NotificationId")
.HasColumnType("bigint");
b.Property<string>("NotificationName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Reason")
.HasMaxLength(255)
.HasColumnType("character varying(255)");
b.Property<DateTime>("SendTime")
.HasColumnType("timestamp without time zone");
b.Property<int>("State")
.HasColumnType("integer");
b.Property<Guid?>("TenantId")
.HasColumnType("uuid")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.Property<string>("UserName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasDefaultValue("/");
b.HasKey("Id");
b.HasIndex("TenantId", "NotificationName")
.HasDatabaseName("IX_Tenant_Send_Notification_Name");
b.ToTable("AppNotificationSendRecords", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b =>
{
b.Property<long>("Id")

5701
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260319053918_Add-AI-Management-Module.Designer.cs

File diff suppressed because it is too large

150
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260319053918_Add-AI-Management-Module.cs

@ -0,0 +1,150 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migrations
{
/// <inheritdoc />
public partial class AddAIManagementModule : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpAIConversations",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Workspace = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
ExpiredAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdateAt = table.Column<DateTime>(type: "datetime2", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAIConversations", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAITextChatMessages",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Content = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Workspace = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Role = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ConversationId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ReplyMessage = table.Column<string>(type: "nvarchar(max)", nullable: true),
ReplyAt = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAITextChatMessages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAITokenUsages",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
MessageId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ConversationId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
InputTokenCount = table.Column<long>(type: "bigint", nullable: true),
OutputTokenCount = table.Column<long>(type: "bigint", nullable: true),
TotalTokenCount = table.Column<long>(type: "bigint", nullable: true),
CachedInputTokenCount = table.Column<long>(type: "bigint", nullable: true),
ReasoningTokenCount = table.Column<long>(type: "bigint", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAITokenUsages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpAIWorkspaceDefinitions",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Provider = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
ModelName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Description = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
ApiKey = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
ApiBaseUrl = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
SystemPrompt = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
Instructions = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
Temperature = table.Column<float>(type: "real", nullable: true),
MaxOutputTokens = table.Column<int>(type: "int", nullable: true),
FrequencyPenalty = table.Column<float>(type: "real", nullable: true),
PresencePenalty = table.Column<float>(type: "real", nullable: true),
IsEnabled = table.Column<bool>(type: "bit", nullable: false),
IsSystem = table.Column<bool>(type: "bit", nullable: false),
StateCheckers = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAIWorkspaceDefinitions", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_AbpAITextChatMessages_TenantId_ConversationId",
table: "AbpAITextChatMessages",
columns: new[] { "TenantId", "ConversationId" });
migrationBuilder.CreateIndex(
name: "IX_AbpAITokenUsages_TenantId_ConversationId",
table: "AbpAITokenUsages",
columns: new[] { "TenantId", "ConversationId" });
migrationBuilder.CreateIndex(
name: "IX_AbpAIWorkspaceDefinitions_Name",
table: "AbpAIWorkspaceDefinitions",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpAIConversations");
migrationBuilder.DropTable(
name: "AbpAITextChatMessages");
migrationBuilder.DropTable(
name: "AbpAITokenUsages");
migrationBuilder.DropTable(
name: "AbpAIWorkspaceDefinitions");
}
}
}

5754
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260324062303_Add-Notification-Send-Record.Designer.cs

File diff suppressed because it is too large

48
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/20260324062303_Add-Notification-Send-Record.cs

@ -0,0 +1,48 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migrations
{
/// <inheritdoc />
public partial class AddNotificationSendRecord : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppNotificationSendRecords",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Provider = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
SendTime = table.Column<DateTime>(type: "datetime2", nullable: false),
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
UserName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false, defaultValue: "/"),
NotificationId = table.Column<long>(type: "bigint", nullable: false),
NotificationName = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: false),
State = table.Column<int>(type: "int", nullable: false),
Reason = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppNotificationSendRecords", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Tenant_Send_Notification_Name",
table: "AppNotificationSendRecords",
columns: new[] { "TenantId", "NotificationName" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppNotificationSendRecords");
}
}
}

332
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer/Migrations/SingleMigrationsDbContextModelSnapshot.cs

@ -24,6 +24,285 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migr
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<DateTime>("ExpiredAt")
.HasColumnType("datetime2");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<DateTime?>("UpdateAt")
.HasColumnType("datetime2");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.HasKey("Id");
b.ToTable("AbpAIConversations", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Content")
.IsRequired()
.HasMaxLength(1024)
.HasColumnType("nvarchar(1024)");
b.Property<Guid?>("ConversationId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<DateTime?>("ReplyAt")
.HasColumnType("datetime2");
b.Property<string>("ReplyMessage")
.HasColumnType("nvarchar(max)");
b.Property<string>("Role")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<Guid?>("UserId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITextChatMessages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<long?>("CachedInputTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("ConversationId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<long?>("InputTokenCount")
.HasColumnType("bigint");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MessageId")
.HasColumnType("uniqueidentifier");
b.Property<long?>("OutputTokenCount")
.HasColumnType("bigint");
b.Property<long?>("ReasoningTokenCount")
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<long?>("TotalTokenCount")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("TenantId", "ConversationId");
b.ToTable("AbpAITokenUsages", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ApiBaseUrl")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("ApiKey")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("Description")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<float?>("FrequencyPenalty")
.HasColumnType("real");
b.Property<string>("Instructions")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<bool>("IsEnabled")
.HasColumnType("bit");
b.Property<bool>("IsSystem")
.HasColumnType("bit");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxOutputTokens")
.HasColumnType("int");
b.Property<string>("ModelName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<float?>("PresencePenalty")
.HasColumnType("real");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");
b.Property<string>("StateCheckers")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("SystemPrompt")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<float?>("Temperature")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpAIWorkspaceDefinitions", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b =>
{
b.Property<Guid>("Id")
@ -1395,6 +1674,59 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.SqlServer.Migr
b.ToTable("AppNotificationDefinitions", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<long>("NotificationId")
.HasColumnType("bigint");
b.Property<string>("NotificationName")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("nvarchar(255)");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("Reason")
.HasMaxLength(255)
.HasColumnType("nvarchar(255)");
b.Property<DateTime>("SendTime")
.HasColumnType("datetime2");
b.Property<int>("State")
.HasColumnType("int");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<Guid>("UserId")
.HasColumnType("uniqueidentifier");
b.Property<string>("UserName")
.IsRequired()
.ValueGeneratedOnAdd()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasDefaultValue("/");
b.HasKey("Id");
b.HasIndex("TenantId", "NotificationName")
.HasDatabaseName("IX_Tenant_Send_Notification_Name");
b.ToTable("AppNotificationSendRecords", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b =>
{
b.Property<long>("Id")

1
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj

@ -24,6 +24,7 @@
<ProjectReference Include="..\..\framework\auditing\LINGYUN.Abp.AuditLogging.EntityFrameworkCore\LINGYUN.Abp.AuditLogging.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\framework\wechat\LINGYUN.Abp.WeChat\LINGYUN.Abp.WeChat.csproj" />
<ProjectReference Include="..\..\framework\common\LINGYUN.Abp.Data.DbMigrator\LINGYUN.Abp.Data.DbMigrator.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.EntityFrameworkCore\LINGYUN.Abp.AIManagement.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>

22
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs

@ -1,4 +1,8 @@
using LINGYUN.Abp.DataProtectionManagement;
using LINGYUN.Abp.AIManagement.Chats;
using LINGYUN.Abp.AIManagement.EntityFrameworkCore;
using LINGYUN.Abp.AIManagement.Tokens;
using LINGYUN.Abp.AIManagement.Workspaces;
using LINGYUN.Abp.DataProtectionManagement;
using LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore;
using LINGYUN.Abp.Demo.Authors;
using LINGYUN.Abp.Demo.Books;
@ -68,6 +72,7 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore;
[ReplaceDbContext(typeof(IAbpDataProtectionManagementDbContext))]
[ReplaceDbContext(typeof(IGdprDbContext))]
[ReplaceDbContext(typeof(IDemoDbContext))]
[ReplaceDbContext(typeof(IAIManagementDbContext))]
[ConnectionStringName("Default")]
public class SingleMigrationsDbContext :
@ -89,7 +94,8 @@ public class SingleMigrationsDbContext :
IMessageServiceDbContext,
IAbpDataProtectionManagementDbContext,
IGdprDbContext,
IDemoDbContext
IDemoDbContext,
IAIManagementDbContext
{
public SingleMigrationsDbContext(DbContextOptions<SingleMigrationsDbContext> options)
: base(options)
@ -199,6 +205,8 @@ public class SingleMigrationsDbContext :
public DbSet<UserSubscribe> UserSubscribes { get; set; }
public DbSet<NotificationSendRecord> NotificationSendRecords { get; set; }
public DbSet<NotificationDefinitionGroupRecord> NotificationDefinitionGroupRecords { get; set; }
public DbSet<NotificationDefinitionRecord> NotificationDefinitionRecords { get; set; }
@ -229,6 +237,14 @@ public class SingleMigrationsDbContext :
public DbSet<Author> Authors { get; set; }
public DbSet<WorkspaceDefinitionRecord> WorkspaceDefinitions { get; set; }
public DbSet<TextChatMessageRecord> TextChatMessageRecords { get; set; }
public DbSet<ConversationRecord> ConversationRecords { get; set; }
public DbSet<TokenUsageRecord> TokenUsageRecords { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
@ -252,5 +268,7 @@ public class SingleMigrationsDbContext :
modelBuilder.ConfigureGdpr();
modelBuilder.ConfigureDemo();
modelBuilder.ConfigureAIManagement();
}
}

2
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs

@ -1,3 +1,4 @@
using LINGYUN.Abp.AIManagement.EntityFrameworkCore;
using LINGYUN.Abp.AuditLogging.EntityFrameworkCore;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.Gdpr.EntityFrameworkCore;
@ -29,6 +30,7 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore;
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpNotificationsEntityFrameworkCoreModule),
typeof(AbpMessageServiceEntityFrameworkCoreModule),
typeof(AbpAIManagementEntityFrameworkCoreModule),
typeof(PlatformEntityFrameworkCoreModule),
typeof(AbpLocalizationManagementEntityFrameworkCoreModule),
typeof(AbpIdentityEntityFrameworkCoreModule),

2
aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageStoreCache.cs

@ -45,6 +45,8 @@ public class LocalizationLanguageStoreCache : ILocalizationLanguageStoreCache, I
new LanguageInfo(x.CultureName, x.UiCultureName, x.DisplayName))
.ToList());
await LanguageCache.SetAsync(LocalizationLanguageCacheItem.CacheKey, cacheItem);
return cacheItem;
}
}

11
aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin5/LINGYUN/Abp/UI/Navigation/VueVbenAdmin5/AbpUINavigationVueVbenAdmin5NavigationDefinitionProvider.cs

@ -485,7 +485,7 @@ public class AbpUINavigationVueVbenAdmin5NavigationDefinitionProvider : Navigati
multiTenancySides: MultiTenancySides.Host)
.SetProperty("title", "abp.manage.notifications.groups"));
notificationManagement.AddItem(new ApplicationMenu(
name: "NotificationsDefinitions",
name: "Vben5NotificationsDefinitions",
displayName: "通知定义",
url: "/manage/notifications/definitions",
component: "/notifications/definitions/index",
@ -493,6 +493,15 @@ public class AbpUINavigationVueVbenAdmin5NavigationDefinitionProvider : Navigati
description: "通知定义",
multiTenancySides: MultiTenancySides.Host)
.SetProperty("title", "abp.manage.notifications.definitions"));
notificationManagement.AddItem(new ApplicationMenu(
name: "Vben5NotificationsSendRecords",
displayName: "发送记录",
url: "/manage/notifications/send-records",
component: "/notifications/send-records/index",
icon: "material-symbols:history",
description: "发送记录",
multiTenancySides: MultiTenancySides.Host)
.SetProperty("title", "abp.manage.notifications.sendRecords"));
manage.AddItem(
new ApplicationMenu(

14
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Dto/NotificationSendRecordDto.cs

@ -0,0 +1,14 @@
using System;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.Notifications;
public class NotificationSendRecordDto : EntityDto<string>
{
public string Provider { get; set; }
public DateTime SendTime { get; set; }
public Guid UserId { get; set; }
public string UserName { get; set; }
public NotificationSendState State { get; set; }
public string Reason { get; set; }
public UserNotificationDto Notification { get; set; }
}

16
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Dto/NotificationSendRecordGetPagedListInput.cs

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.Notifications;
#nullable enable
public class NotificationSendRecordGetPagedListInput : PagedAndSortedResultRequestDto
{
public string? Provider { get; set; }
public DateTime? BeginSendTime { get; set; }
public DateTime? EndSendTime { get; set; }
public Guid? UserId { get; set; }
public string? NotificationName { get; set; }
public NotificationSendState? State { get; set; }
}
#nullable disable

5
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Dto/UserNotificationGetByPagedDto.cs

@ -1,4 +1,5 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.Notifications;
@ -9,4 +10,6 @@ public class UserNotificationGetByPagedDto : PagedAndSortedResultRequestDto
[DisplayName("Notifications:State")]
public NotificationReadState? ReadState { get; set; }
public DateTime? BeginCreationTime { get; set; }
public DateTime? EndCreationTime { get; set; }
}

13
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/INotificationSendRecordAppService.cs

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.Notifications;
public interface INotificationSendRecordAppService : IApplicationService
{
Task DeleteAsync(long id);
Task ReSendAsync(long id);
Task<PagedResultDto<NotificationSendRecordDto>> GetListAsync(NotificationSendRecordGetPagedListInput input);
}

6
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Permissions/NotificationsPermissions.cs

@ -10,6 +10,12 @@ public class NotificationsPermissions
public const string Delete = Default + ".Delete";
public const string Send = Default + ".Send";
public static class SendRecord
{
public const string Default = Notification.Default + ".SendRecord";
public const string ReSend = Default + ".ReSend";
public const string Delete = Default + ".Delete";
}
}
public static class GroupDefinition

5
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application.Contracts/LINGYUN/Abp/Notifications/Permissions/NotificationsPermissionsDefinitionProvider.cs

@ -48,6 +48,11 @@ public class NotificationsPermissionsDefinitionProvider : PermissionDefinitionPr
var noticeGroup = group.AddPermission(NotificationsPermissions.Notification.Default, L("Permission:Notification"));
noticeGroup.AddChild(NotificationsPermissions.Notification.Delete, L("Permission:Delete"));
noticeGroup.AddChild(NotificationsPermissions.Notification.Send, L("Permission:Send"));
var notificationSendPermission = noticeGroup.AddChild(
NotificationsPermissions.Notification.SendRecord.Default,
L("Permission:SendRecord"));
notificationSendPermission.AddChild(NotificationsPermissions.Notification.SendRecord.Delete, L("Permission:Delete"));
notificationSendPermission.AddChild(NotificationsPermissions.Notification.SendRecord.ReSend, L("Permission:ReSend"));
}
private static LocalizableString L(string name)

26
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/AbpNotificationsApplicationMappers.cs

@ -33,3 +33,29 @@ public partial class UserNotificationInfoToUserNotificationDtoMapper : MapperBas
return new NotificationData();
}
}
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
public partial class NotificationSendRecordInfoToNotificationSendRecordDtoMapper : MapperBase<NotificationSendRecordInfo, NotificationSendRecordDto>
{
private readonly UserNotificationInfoToUserNotificationDtoMapper _userNotificationInfoMapper;
public NotificationSendRecordInfoToNotificationSendRecordDtoMapper(UserNotificationInfoToUserNotificationDtoMapper userNotificationInfoMapper)
{
_userNotificationInfoMapper = userNotificationInfoMapper;
}
[MapProperty(nameof(NotificationSendRecordInfo.Id), nameof(NotificationSendRecordDto.Id))]
public override partial NotificationSendRecordDto Map(NotificationSendRecordInfo source);
[MapProperty(nameof(NotificationSendRecordInfo.Id), nameof(NotificationSendRecordDto.Id))]
public override partial void Map(NotificationSendRecordInfo source, NotificationSendRecordDto destination);
public override void AfterMap(NotificationSendRecordInfo source, NotificationSendRecordDto destination)
{
if (source.NotificationInfo != null)
{
var userNotificationInfoDto = _userNotificationInfoMapper.Map(source.NotificationInfo);
_userNotificationInfoMapper.AfterMap(source.NotificationInfo, userNotificationInfoDto);
destination.Notification = userNotificationInfoDto;
}
}
}

38
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/MyNotificationAppService.cs

@ -1,5 +1,8 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Users;
@ -56,17 +59,34 @@ public class MyNotificationAppService : AbpNotificationsApplicationServiceBase,
public async virtual Task<PagedResultDto<UserNotificationDto>> GetListAsync(UserNotificationGetByPagedDto input)
{
var totalCount = await UserNotificationRepository
.GetCountAsync(
CurrentUser.GetId(),
input.Filter,
input.ReadState);
Expression<Func<UserNotificationInfo, bool>> expression = _ => true;
if (input.ReadState.HasValue)
{
expression = expression.And(x => x.State == input.ReadState);
}
if (input.BeginCreationTime.HasValue)
{
expression = expression.And(x => x.CreationTime >= input.BeginCreationTime);
}
if (input.EndCreationTime.HasValue)
{
expression = expression.And(x => x.CreationTime <= input.EndCreationTime);
}
if (!input.Filter.IsNullOrWhiteSpace())
{
expression = expression.And(x =>
x.Name.Contains(input.Filter) ||
x.NotificationTypeName.Contains(input.Filter));
}
var specification = new Volo.Abp.Specifications.ExpressionSpecification<UserNotificationInfo>(expression);
var userId = CurrentUser.GetId();
var totalCount = await UserNotificationRepository.GetCountAsync(userId, specification);
var notifications = await UserNotificationRepository
.GetListAsync(
CurrentUser.GetId(),
input.Filter, input.Sorting,
input.ReadState, input.SkipCount, input.MaxResultCount);
.GetListAsync(userId, specification, input.Sorting, input.SkipCount, input.MaxResultCount);
return new PagedResultDto<UserNotificationDto>(totalCount,
ObjectMapper.Map<List<UserNotificationInfo>, List<UserNotificationDto>>(notifications));

107
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/NotificationSendRecordAppService.cs

@ -0,0 +1,107 @@
using LINGYUN.Abp.Notifications.Permissions;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.Notifications;
[Authorize(NotificationsPermissions.Notification.SendRecord.Default)]
public class NotificationSendRecordAppService : AbpNotificationsApplicationServiceBase, INotificationSendRecordAppService
{
private readonly INotificationSendRecordRepository _repository;
protected INotificationStore NotificationStore => LazyServiceProvider.LazyGetRequiredService<INotificationStore>();
protected INotificationSender NotificationSender => LazyServiceProvider.LazyGetRequiredService<INotificationSender>();
protected INotificationDefinitionManager NotificationDefinitionManager => LazyServiceProvider.LazyGetRequiredService<INotificationDefinitionManager>();
public NotificationSendRecordAppService(INotificationSendRecordRepository repository)
{
_repository = repository;
}
[Authorize(NotificationsPermissions.Notification.SendRecord.Delete)]
public async virtual Task DeleteAsync(long id)
{
var sendRecord = await _repository.GetAsync(id);
await _repository.DeleteAsync(sendRecord);
}
[Authorize(NotificationsPermissions.Notification.SendRecord.ReSend)]
public async virtual Task ReSendAsync(long id)
{
var sendRecord = await _repository.GetAsync(id);
var notificationInfo = await NotificationStore.GetNotificationOrNullAsync(sendRecord.TenantId, sendRecord.NotificationId);
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(notificationInfo.Name);
if (notificationDefine?.Template != null)
{
var template = new NotificationTemplate(
notificationInfo.Name,
data: notificationInfo.Data.ExtraProperties);
await NotificationSender.SendNofiterAsync(
notificationInfo.Name,
template,
[new UserIdentifier(sendRecord.UserId, sendRecord.UserName)],
sendRecord.TenantId,
notificationInfo.Severity,
[sendRecord.Provider]);
}
else
{
await NotificationSender.SendNofiterAsync(
notificationInfo.Name,
notificationInfo.Data,
[new UserIdentifier(sendRecord.UserId, sendRecord.UserName)],
sendRecord.TenantId,
notificationInfo.Severity,
[sendRecord.Provider]);
}
}
public async virtual Task<PagedResultDto<NotificationSendRecordDto>> GetListAsync(NotificationSendRecordGetPagedListInput input)
{
Expression<Func<NotificationSendRecordInfo, bool>> expression = _ => true;
if (input.State.HasValue)
{
expression = expression.And(x => x.State == input.State);
}
if (!input.Provider.IsNullOrWhiteSpace())
{
expression = expression.And(x => x.Provider == input.Provider);
}
if (!input.NotificationName.IsNullOrWhiteSpace())
{
expression = expression.And(x => x.NotificationInfo.Name == input.NotificationName);
}
if (input.UserId.HasValue)
{
expression = expression.And(x => x.UserId == input.UserId);
}
if (input.BeginSendTime.HasValue)
{
expression = expression.And(x => x.SendTime >= input.BeginSendTime);
}
if (input.EndSendTime.HasValue)
{
expression = expression.And(x => x.SendTime <= input.EndSendTime);
}
var specification = new ExpressionSpecification<NotificationSendRecordInfo>(expression);
var totalCount = await _repository.GetCountAsync(specification);
var list = await _repository.GetListAsync(specification,
input.Sorting, input.MaxResultCount, input.SkipCount);
return new PagedResultDto<NotificationSendRecordDto>(totalCount,
ObjectMapper.Map<List<NotificationSendRecordInfo>, List<NotificationSendRecordDto>>(list));
}
}

35
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationPublishContext.cs

@ -0,0 +1,35 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.Notifications;
#nullable enable
public class NotificationPublishContext
{
[NotNull]
public NotificationInfo Notification { get; }
[CanBeNull]
public IEnumerable<UserIdentifier> Users { get; }
[CanBeNull]
public string? Reason { get; private set; }
[CanBeNull]
public Exception? Exception { get; private set; }
public NotificationPublishContext(
NotificationInfo notification,
IEnumerable<UserIdentifier> users)
{
Notification = notification;
Users = users;
}
public void Cancel(string reason, Exception exception = null)
{
Reason = reason;
Exception = exception;
}
}
#nullable disable

49
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationSendInfo.cs

@ -0,0 +1,49 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using Volo.Abp;
namespace LINGYUN.Abp.Notifications;
public class NotificationSendInfo
{
public string Provider { get; }
public DateTime SendTime { get; }
public NotificationInfo NotificationInfo { get; }
public IEnumerable<UserIdentifier> Users { get; }
public NotificationSendState State { get; private set; }
public string Reason { get; private set; }
public NotificationSendInfo(
[NotNull] string provider,
DateTime sendTime,
NotificationInfo notificationInfo,
IEnumerable<UserIdentifier> users)
{
Check.NotNullOrWhiteSpace(provider, nameof(provider));
Check.NotNull(notificationInfo, nameof(notificationInfo));
Check.NotNull(users, nameof(users));
Provider = provider;
SendTime = sendTime;
NotificationInfo = notificationInfo;
Users = users;
State = NotificationSendState.None;
}
public void Cancel(string reason)
{
State = NotificationSendState.None;
Reason = reason;
}
public void Disbaled()
{
State = NotificationSendState.Disabled;
}
public void Sent(Exception exception = null)
{
State = exception != null ? NotificationSendState.Failed : NotificationSendState.Sent;
Reason = exception?.Message;
}
}

23
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Core/LINGYUN/Abp/Notifications/NotificationSendState.cs

@ -0,0 +1,23 @@
namespace LINGYUN.Abp.Notifications;
/// <summary>
/// 发送状态
/// </summary>
public enum NotificationSendState
{
/// <summary>
/// 未发送
/// </summary>
None,
/// <summary>
/// 提供者禁用
/// </summary>
Disabled,
/// <summary>
/// 已发送
/// </summary>
Sent,
/// <summary>
/// 发送失败
/// </summary>
Failed
}

6
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/AbpNotificationsDomainSharedModule.cs

@ -1,5 +1,6 @@
using LINGYUN.Abp.Notifications.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Users;
using Volo.Abp.VirtualFileSystem;
@ -24,5 +25,10 @@ public class AbpNotificationsDomainSharedModule : AbpModule
.Get<NotificationsResource>()
.AddVirtualJson("/LINGYUN/Abp/Notifications/Localization/DomainShared");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(NotificationsErrorCodes.Namespace, typeof(NotificationsResource));
});
}
}

17
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/Localization/DomainShared/en.json

@ -5,10 +5,12 @@
"Permission:GroupDefinitions": "Group Definitions",
"Permission:NotificationDefinitions": "Notification Definitions",
"Permission:Notification": "Manage Notification",
"Permission:SendRecord": "Send Records",
"Permission:Create": "Create",
"Permission:Edit": "Edit",
"Permission:Delete": "Delete",
"Permission:Send": "Send",
"Permission:ReSend": "Re Send",
"Notifications:001404": "The notification template does not exist!",
"Notifications:002400": "The static notification group {Name} is not allowed to change!",
"Notifications:002403": "Notification that the {Name} group already exists!",
@ -34,6 +36,11 @@
"DisplayName:Template": "Template",
"Description:Template": "The notification template is required when sending template notifications.",
"DisplayName:IsStatic": "Static",
"DisplayName:SendTime": "Send Time",
"DisplayName:Provider": "Provider",
"DisplayName:NotificationName": "Notification Name",
"DisplayName:SendState": "Send State",
"DisplayName:UserName": "User Name",
"Providers:Emailing": "Email",
"Providers:SignalR": "SignalR",
"Providers:Sms": "Sms",
@ -49,6 +56,14 @@
"TemplateContent": "Template Content",
"ItemWillBeDeleteOrRestoreMessage": "If the notification has been changed, it will revert to the default notification. Otherwise, the custom notification is removed.",
"Notifications:Send": "Send Notification",
"SendSuccessfully": "Send Successfully"
"SendSuccessfully": "Send Successfully",
"SendRecords": "Send Records",
"Resend": "Re Send",
"NotificationSendState:None": "None",
"NotificationSendState:Disabled": "Disabled",
"NotificationSendState:Sent": "Sent",
"NotificationSendState:Failed": "Failed",
"SelectedSendRecordWillBeDeleteMessage": "The selected sent messages will be deleted!",
"SelectedSendRecordWillBeReSendMessage": "Send the record of the notification for the re-sending of the selection!"
}
}

17
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/Localization/DomainShared/zh-Hans.json

@ -5,10 +5,12 @@
"Permission:GroupDefinitions": "分组定义",
"Permission:NotificationDefinitions": "通知定义",
"Permission:Notification": "管理通知",
"Permission:SendRecord": "发送记录",
"Permission:Create": "新增",
"Permission:Edit": "编辑",
"Permission:Delete": "删除",
"Permission:Send": "发送通知",
"Permission:ReSend": "重新发送",
"Notifications:001404": "通知模板不存在!",
"Notifications:002400": "静态通知分组 {Name} 不允许变更!",
"Notifications:002403": "通知分组 {Name} 已经存在!",
@ -34,6 +36,11 @@
"DisplayName:Template": "模板",
"Description:Template": "发送模板通知时需要提供通知模板.",
"DisplayName:IsStatic": "静态",
"DisplayName:SendTime": "发送时间",
"DisplayName:Provider": "提供者",
"DisplayName:NotificationName": "通知名称",
"DisplayName:SendState": "发送状态",
"DisplayName:UserName": "用户名",
"Providers:Emailing": "邮件",
"Providers:SignalR": "SignalR",
"Providers:Sms": "短信",
@ -49,6 +56,14 @@
"TemplateContent": "模板内容",
"ItemWillBeDeleteOrRestoreMessage": "如果已改变通知, 将还原到默认通知。否则会删除自定义通知.",
"Notifications:Send": "发送通知",
"SendSuccessfully": "发送成功"
"SendSuccessfully": "发送成功",
"SendRecords": "发送记录",
"Resend": "重新发送",
"NotificationSendState:None": "未发送",
"NotificationSendState:Disabled": "提供者禁用",
"NotificationSendState:Sent": "已发送",
"NotificationSendState:Failed": "发送失败",
"SelectedSendRecordWillBeDeleteMessage": "选择的发送记录将被删除!",
"SelectedSendRecordWillBeReSendMessage": "将重新发送选择的通知发送记录!"
}
}

6
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain.Shared/LINGYUN/Abp/Notifications/NotificationSendRecordConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.Notifications;
public static class NotificationSendRecordConsts
{
public static int MaxProviderLength { get; set; } = 50;
public static int MaxReasonLength { get; set; } = 255;
}

20
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/INotificationSendRecordRepository.cs

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.Notifications;
public interface INotificationSendRecordRepository : IBasicRepository<NotificationSendRecord, long>
{
Task<int> GetCountAsync(
ISpecification<NotificationSendRecordInfo> specification,
CancellationToken cancellationToken = default);
Task<List<NotificationSendRecordInfo>> GetListAsync(
ISpecification<NotificationSendRecordInfo> specification,
string sorting = $"{nameof(NotificationSendRecordInfo.SendTime)} DESC",
int maxResultCount = 10,
int skipCount = 0,
CancellationToken cancellationToken = default);
}

14
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/IUserNotificationRepository.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.Notifications;
@ -47,4 +48,17 @@ public interface IUserNotificationRepository : IBasicRepository<UserNotification
int skipCount = 0,
int maxResultCount = 10,
CancellationToken cancellationToken = default);
Task<int> GetCountAsync(
Guid userId,
ISpecification<UserNotificationInfo> specification,
CancellationToken cancellationToken = default);
Task<List<UserNotificationInfo>> GetListAsync(
Guid userId,
ISpecification<UserNotificationInfo> specification,
string sorting = nameof(Notification.CreationTime),
int skipCount = 0,
int maxResultCount = 10,
CancellationToken cancellationToken = default);
}

48
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/NotificationSendRecord.cs

@ -0,0 +1,48 @@
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Notifications;
public class NotificationSendRecord : Entity<long>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual string Provider { get; protected set; }
public virtual DateTime SendTime { get; protected set; }
public virtual Guid UserId { get; protected set; }
public virtual string UserName { get; protected set; }
public virtual long NotificationId { get; protected set; }
public virtual string NotificationName { get; protected set; }
public virtual NotificationSendState State { get; protected set; }
public virtual string Reason { get; protected set; }
protected NotificationSendRecord()
{
}
public NotificationSendRecord(
string provider,
DateTime sendTime,
Guid userId,
string userName,
long notificationId,
string notificationName,
NotificationSendState state,
string reason = null,
Guid? tenantId = null)
{
Provider = Check.NotNullOrWhiteSpace(provider, nameof(provider), NotificationSendRecordConsts.MaxProviderLength);
SendTime = sendTime;
UserId = userId;
UserName = Check.Length(userName, nameof(userName), SubscribeConsts.MaxUserNameLength);
NotificationId = notificationId;
NotificationName = Check.NotNullOrWhiteSpace(notificationName, nameof(notificationName), NotificationConsts.MaxNameLength);
State = state;
Reason = reason;
TenantId = tenantId;
if (!Reason.IsNullOrWhiteSpace() && Reason.Length > NotificationSendRecordConsts.MaxReasonLength)
{
Reason = Reason.Substring(0, NotificationSendRecordConsts.MaxReasonLength);
}
}
}

14
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/NotificationSendRecordInfo.cs

@ -0,0 +1,14 @@
using System;
namespace LINGYUN.Abp.Notifications;
public class NotificationSendRecordInfo
{
public long Id { get; set; }
public string Provider { get; set; }
public DateTime SendTime { get; set; }
public Guid UserId { get; set; }
public string UserName { get; set; }
public NotificationSendState State { get; set; }
public string Reason { get; set; }
public UserNotificationInfo NotificationInfo { get; set; }
}

33
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/NotificationStore.cs

@ -25,6 +25,8 @@ public class NotificationStore : INotificationStore
private readonly INotificationRepository _notificationRepository;
private readonly INotificationSendRecordRepository _notificationSendRecordRepository;
private readonly IUserNotificationRepository _userNotificationRepository;
private readonly IUserSubscribeRepository _userSubscribeRepository;
@ -40,6 +42,7 @@ public class NotificationStore : INotificationStore
INotificationRepository notificationRepository,
IUserSubscribeRepository userSubscribeRepository,
IUserNotificationRepository userNotificationRepository,
INotificationSendRecordRepository notificationSendRecordRepository,
IOptions<AbpNotificationsPublishOptions> options,
IObjectMapper<AbpNotificationsDomainModule> objectMapper)
{
@ -50,10 +53,40 @@ public class NotificationStore : INotificationStore
_notificationRepository = notificationRepository;
_userSubscribeRepository = userSubscribeRepository;
_userNotificationRepository = userNotificationRepository;
_notificationSendRecordRepository = notificationSendRecordRepository;
_options = options.Value;
}
public async virtual Task InsertSendStateAsync(
NotificationSendInfo notificationSendInfo,
CancellationToken cancellationToken = default)
{
if (!notificationSendInfo.Users.Any())
{
return;
}
var notificationSendRecords = notificationSendInfo.Users
.Select(user => new NotificationSendRecord(
notificationSendInfo.Provider,
notificationSendInfo.SendTime,
user.UserId,
user.UserName,
notificationSendInfo.NotificationInfo.GetId(),
notificationSendInfo.NotificationInfo.Name,
notificationSendInfo.State,
notificationSendInfo.Reason,
notificationSendInfo.NotificationInfo.TenantId));
using (var unitOfWork = _unitOfWorkManager.Begin())
using (_currentTenant.Change(notificationSendInfo.NotificationInfo.TenantId))
{
await _notificationSendRecordRepository.InsertManyAsync(notificationSendRecords);
await unitOfWork.CompleteAsync();
}
}
public async virtual Task ChangeUserNotificationReadStateAsync(
Guid? tenantId,
Guid userId,

15
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Emailing/LINGYUN/Abp/Notifications/Emailing/EmailingNotificationPublishProvider.cs

@ -21,11 +21,10 @@ public class EmailingNotificationPublishProvider : NotificationPublishProvider
protected INotificationDataSerializer NotificationDataSerializer => ServiceProvider.LazyGetRequiredService<INotificationDataSerializer>();
protected async override Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
NotificationPublishContext context,
CancellationToken cancellationToken = default)
{
var userIds = identifiers.Select(x => x.UserId).ToList();
var userIds = context.Users.Select(x => x.UserId).ToList();
var userList = await UserRepository.GetListByIdListAsync(userIds, cancellationToken: cancellationToken);
var emailAddress = userList
@ -47,19 +46,21 @@ public class EmailingNotificationPublishProvider : NotificationPublishProvider
if (emailAddress.IsNullOrWhiteSpace())
{
Logger.LogWarning("The subscriber did not confirm the email address and could not send email notifications!");
var reason = "The subscriber did not confirm the email address and could not send email notifications!";
Logger.LogWarning(reason);
context.Cancel(reason);
return;
}
var notificationData = await NotificationDataSerializer.ToStandard(notification.Data);
var notificationData = await NotificationDataSerializer.ToStandard(context.Notification.Data);
// markdown进行处理
if (notification.ContentType == NotificationContentType.Markdown)
if (context.Notification.ContentType == NotificationContentType.Markdown)
{
notificationData.Message = Markdown.ToHtml(notificationData.Message);
}
await EmailSender.SendAsync(emailAddress, notificationData.Title, notificationData.Message);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
}

2
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/AbpNotificationsEntityFrameworkCoreModule.cs

@ -19,6 +19,8 @@ public class AbpNotificationsEntityFrameworkCoreModule : AbpModule
options.AddRepository<UserNotification, EfCoreUserNotificationRepository>();
options.AddRepository<UserSubscribe, EfCoreUserSubscribeRepository>();
options.AddRepository<NotificationSendRecord, EfCoreNotificationSendRecordRepository>();
});
context.Services.AddAbpDbContext<NotificationsDefinitionDbContext>(options =>

99
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/EfCoreNotificationSendRecordRepository.cs

@ -0,0 +1,99 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.Notifications.EntityFrameworkCore;
public class EfCoreNotificationSendRecordRepository :
EfCoreRepository<INotificationsDbContext, NotificationSendRecord, long>,
INotificationSendRecordRepository
{
public EfCoreNotificationSendRecordRepository(
IDbContextProvider<INotificationsDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async virtual Task<int> GetCountAsync(
ISpecification<NotificationSendRecordInfo> specification,
CancellationToken cancellationToken = default)
{
return await (await GetSendRecordInfoAsync())
.Where(specification.ToExpression())
.CountAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<List<NotificationSendRecordInfo>> GetListAsync(
ISpecification<NotificationSendRecordInfo> specification,
string sorting = $"{nameof(NotificationSendRecordInfo.SendTime)} DESC",
int maxResultCount = 10,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
return await (await GetSendRecordInfoAsync())
.Where(specification.ToExpression())
.OrderBy(!sorting.IsNullOrWhiteSpace() ? sorting : $"{nameof(NotificationSendRecordInfo.SendTime)} DESC")
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
protected async virtual Task<IQueryable<NotificationSendRecordInfo>> GetSendRecordInfoAsync()
{
var dbContext = await GetDbContextAsync();
return dbContext.Set<Notification>()
.Join(
dbContext.Set<UserNotification>(),
n => n.NotificationId,
un => un.NotificationId,
(n, un) => new
{
NotificationId = n.NotificationId,
NotificationName = n.NotificationName,
NotificationTypeName = n.NotificationTypeName,
TenantId = n.TenantId,
Type = n.Type,
Severity = n.Severity,
ContentType = n.ContentType,
CreationTime = n.CreationTime,
ExtraProperties = n.ExtraProperties,
State = un.ReadStatus,
UserId = un.UserId,
Id = un.Id,
})
.Join(
dbContext.Set<NotificationSendRecord>(),
un => new { un.UserId, un.NotificationId },
nsr => new { nsr.UserId, nsr.NotificationId },
(un, nsr) => new NotificationSendRecordInfo
{
Id = nsr.Id,
UserId = nsr.UserId,
UserName = nsr.UserName,
Provider = nsr.Provider,
State = nsr.State,
Reason = nsr.Reason,
SendTime = nsr.SendTime,
NotificationInfo = new UserNotificationInfo
{
TenantId = un.TenantId,
Type = un.Type,
Severity = un.Severity,
ContentType = un.ContentType,
CreationTime = un.CreationTime,
ExtraProperties = un.ExtraProperties,
NotificationId = un.NotificationId,
NotificationTypeName = un.NotificationTypeName,
Name = un.NotificationName,
State = un.State,
Id = un.Id,
},
});
}
}

81
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/EfCoreUserNotificationRepository.cs

@ -1,13 +1,16 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.Notifications.EntityFrameworkCore;
@ -151,6 +154,35 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
.CountAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<int> GetCountAsync(
Guid userId,
ISpecification<UserNotificationInfo> specification,
CancellationToken cancellationToken = default)
{
var dbContext = await GetDbContextAsync();
var notifilerQuery = from un in dbContext.Set<UserNotification>()
join n in dbContext.Set<Notification>()
on un.NotificationId equals n.NotificationId
where un.UserId == userId
select new UserNotificationInfo
{
NotificationId = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
CreationTime = n.CreationTime,
NotificationTypeName = n.NotificationTypeName,
Severity = n.Severity,
State = un.ReadStatus,
Type = n.Type,
ContentType = n.ContentType
};
return await notifilerQuery
.Where(specification.ToExpression())
.CountAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<List<UserNotificationInfo>> GetListAsync(
Guid userId,
string filter = "",
@ -165,14 +197,6 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
sorting = $"{nameof(Notification.CreationTime)} DESC";
}
var dbContext = await GetDbContextAsync();
//var userNotifilerQuery = dbContext.Set<UserNotification>()
// .Where(x => x.UserId == userId)
// .WhereIf(readState.HasValue, x => x.ReadStatus == readState.Value);
//var notificationQuery = dbContext.Set<Notification>()
// .WhereIf(!filter.IsNullOrWhiteSpace(), nf =>
// nf.NotificationName.Contains(filter) ||
// nf.NotificationTypeName.Contains(filter));
var notifilerQuery = from un in dbContext.Set<UserNotification>()
join n in dbContext.Set<Notification>()
@ -202,4 +226,45 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
.AsNoTracking()
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<List<UserNotificationInfo>> GetListAsync(
Guid userId,
ISpecification<UserNotificationInfo> specification,
string sorting = nameof(Notification.CreationTime),
int skipCount = 0,
int maxResultCount = 10,
CancellationToken cancellationToken = default)
{
if (sorting.IsNullOrWhiteSpace())
{
sorting = $"{nameof(Notification.CreationTime)} DESC";
}
var dbContext = await GetDbContextAsync();
var notifilerQuery = from un in dbContext.Set<UserNotification>()
join n in dbContext.Set<Notification>()
on un.NotificationId equals n.NotificationId
where un.UserId == userId
select new UserNotificationInfo
{
NotificationId = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
CreationTime = n.CreationTime,
NotificationTypeName = n.NotificationTypeName,
Severity = n.Severity,
State = un.ReadStatus,
Type = n.Type,
ContentType = n.ContentType,
Id = un.Id,
};
return await notifilerQuery
.Where(specification.ToExpression())
.OrderBy(sorting)
.PageBy(skipCount, maxResultCount)
.AsNoTracking()
.ToListAsync(GetCancellationToken(cancellationToken));
}
}

4
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/INotificationsDbContext.cs

@ -10,7 +10,5 @@ public interface INotificationsDbContext : IEfCoreDbContext
DbSet<Notification> Notifications { get; }
DbSet<UserNotification> UserNotifications { get; }
DbSet<UserSubscribe> UserSubscribes { get; }
DbSet<NotificationDefinitionGroupRecord> NotificationDefinitionGroupRecords { get; }
DbSet<NotificationDefinitionRecord> NotificationDefinitionRecords { get; }
DbSet<NotificationSendRecord> NotificationSendRecords { get; }
}

4
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/NotificationsDbContext.cs

@ -10,9 +10,7 @@ public class NotificationsDbContext : AbpDbContext<NotificationsDbContext>, INot
public DbSet<Notification> Notifications { get; set; }
public DbSet<UserNotification> UserNotifications { get; set; }
public DbSet<UserSubscribe> UserSubscribes { get; set; }
public DbSet<NotificationDefinitionGroupRecord> NotificationDefinitionGroupRecords { get; set; }
public DbSet<NotificationDefinitionRecord> NotificationDefinitionRecords { get; set; }
public DbSet<NotificationSendRecord> NotificationSendRecords { get; set; }
public NotificationsDbContext(DbContextOptions<NotificationsDbContext> options)
: base(options)

99
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/NotificationsDbContextModelCreatingExtensions.cs

@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
@ -60,6 +59,25 @@ public static class NotificationsDbContextModelCreatingExtensions
.HasDatabaseName("IX_Tenant_User_Notification_Name")
.IsUnique();
});
builder.Entity<NotificationSendRecord>(b =>
{
b.ToTable(options.TablePrefix + "NotificationSendRecords", options.Schema);
b.Property(p => p.Provider).HasMaxLength(NotificationSendRecordConsts.MaxProviderLength).IsRequired();
b.Property(p => p.NotificationName).HasMaxLength(NotificationConsts.MaxNameLength).IsRequired();
b.Property(p => p.UserName)
.HasMaxLength(SubscribeConsts.MaxUserNameLength)
.HasDefaultValue("/")// 不是必须的
.IsRequired();
b.Property(p => p.Reason).HasMaxLength(NotificationSendRecordConsts.MaxReasonLength);
b.ConfigureByConvention();
b.HasIndex(p => new { p.TenantId, p.NotificationName })
.HasDatabaseName("IX_Tenant_Send_Notification_Name");
});
}
public static void ConfigureNotificationsDefinition(
@ -72,44 +90,47 @@ public static class NotificationsDbContextModelCreatingExtensions
optionsAction?.Invoke(options);
builder.Entity<NotificationDefinitionGroupRecord>(b =>
if (builder.IsHostDatabase())
{
b.ToTable(options.TablePrefix + "NotificationDefinitionGroups", options.Schema);
b.Property(p => p.Name)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxNameLength)
.IsRequired();
b.Property(p => p.DisplayName)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxDisplayNameLength);
b.Property(p => p.Description)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxDescriptionLength);
b.ConfigureByConvention();
});
builder.Entity<NotificationDefinitionRecord>(b =>
{
b.ToTable(options.TablePrefix + "NotificationDefinitions", options.Schema);
b.Property(p => p.Name)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxNameLength)
.IsRequired();
b.Property(p => p.GroupName)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxNameLength)
.IsRequired();
b.Property(p => p.DisplayName)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxDisplayNameLength);
b.Property(p => p.Description)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxDescriptionLength);
b.Property(p => p.Providers)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxProvidersLength);
b.Property(p => p.Template)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxTemplateLength);
b.Property(p => p.ContentType)
.HasDefaultValue(NotificationContentType.Text);
b.ConfigureByConvention();
});
builder.Entity<NotificationDefinitionGroupRecord>(b =>
{
b.ToTable(options.TablePrefix + "NotificationDefinitionGroups", options.Schema);
b.Property(p => p.Name)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxNameLength)
.IsRequired();
b.Property(p => p.DisplayName)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxDisplayNameLength);
b.Property(p => p.Description)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxDescriptionLength);
b.ConfigureByConvention();
});
builder.Entity<NotificationDefinitionRecord>(b =>
{
b.ToTable(options.TablePrefix + "NotificationDefinitions", options.Schema);
b.Property(p => p.Name)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxNameLength)
.IsRequired();
b.Property(p => p.GroupName)
.HasMaxLength(NotificationDefinitionGroupRecordConsts.MaxNameLength)
.IsRequired();
b.Property(p => p.DisplayName)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxDisplayNameLength);
b.Property(p => p.Description)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxDescriptionLength);
b.Property(p => p.Providers)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxProvidersLength);
b.Property(p => p.Template)
.HasMaxLength(NotificationDefinitionRecordConsts.MaxTemplateLength);
b.Property(p => p.ContentType)
.HasDefaultValue(NotificationContentType.Text);
b.ConfigureByConvention();
});
}
}
}

45
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.HttpApi/LINGYUN/Abp/Notifications/NotificationSendRecordController.cs

@ -0,0 +1,45 @@
using LINGYUN.Abp.Notifications.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Abp.Notifications;
[Controller]
[RemoteService(Name = AbpNotificationsRemoteServiceConsts.RemoteServiceName)]
[Area(AbpNotificationsRemoteServiceConsts.ModuleName)]
[Route("api/notifications/send-records")]
[Authorize(NotificationsPermissions.Notification.SendRecord.Default)]
public class NotificationSendRecordController : AbpControllerBase, INotificationSendRecordAppService
{
private readonly INotificationSendRecordAppService _service;
public NotificationSendRecordController(INotificationSendRecordAppService service)
{
_service = service;
}
[HttpDelete]
[Route("{id}")]
[Authorize(NotificationsPermissions.Notification.SendRecord.Delete)]
public virtual Task DeleteAsync(long id)
{
return _service.DeleteAsync(id);
}
[HttpGet]
public virtual Task<PagedResultDto<NotificationSendRecordDto>> GetListAsync(NotificationSendRecordGetPagedListInput input)
{
return _service.GetListAsync(input);
}
[HttpPost]
[Route("{id}/re-send")]
[Authorize(NotificationsPermissions.Notification.SendRecord.ReSend)]
public virtual Task ReSendAsync(long id)
{
return _service.ReSendAsync(id);
}
}

13
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.PushPlus/LINGYUN/Abp/Notifications/PushPlus/PushPlusNotificationPublishProvider.cs

@ -35,13 +35,12 @@ public class PushPlusNotificationPublishProvider : NotificationPublishProvider
}
protected async override Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
NotificationPublishContext context,
CancellationToken cancellationToken = default)
{
var topic = "";
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(notification.Name);
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(context.Notification.Name);
var topicDefine = notificationDefine?.GetTopicOrNull();
if (!topicDefine.IsNullOrWhiteSpace())
{
@ -51,9 +50,9 @@ public class PushPlusNotificationPublishProvider : NotificationPublishProvider
?? PushPlusChannelType.Email;
var template = notificationDefine?.GetTemplateOrDefault(PushPlusMessageTemplate.Text)
?? PushPlusMessageTemplate.Text;
var webhook = notification.Data.GetWebhookOrNull() ?? "";
var callbackUrl = notification.Data.GetCallbackUrlOrNull() ?? "";
var notificationData = await NotificationDataSerializer.ToStandard(notification.Data);
var webhook = context.Notification.Data.GetWebhookOrNull() ?? "";
var callbackUrl = context.Notification.Data.GetCallbackUrlOrNull() ?? "";
var notificationData = await NotificationDataSerializer.ToStandard(context.Notification.Data);
await PushPlusMessageSender.SendWithChannelAsync(
notificationData.Title,
@ -65,6 +64,6 @@ public class PushPlusNotificationPublishProvider : NotificationPublishProvider
callbackUrl: callbackUrl,
cancellationToken: cancellationToken);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
}

23
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs

@ -27,40 +27,43 @@ public class SignalRNotificationPublishProvider : NotificationPublishProvider
}
protected async override Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
NotificationPublishContext context,
CancellationToken cancellationToken = default)
{
if (identifiers?.Count() == 0)
if (!context.Users.Any())
{
var groupName = notification.TenantId?.ToString() ?? "Global";
var groupName = context.Notification.TenantId?.ToString() ?? "Global";
try
{
var singalRGroup = _hubContext.Clients.Group(groupName);
// 租户通知群发
Logger.LogDebug($"Found a singalr group, begin senging notifications");
await singalRGroup.SendAsync(_options.MethodName, notification, cancellationToken);
await singalRGroup.SendAsync(_options.MethodName, context.Notification, cancellationToken);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
catch (Exception ex)
{
Logger.LogWarning("Could not send notifications to group {0}", groupName);
Logger.LogWarning("Send to user notifications error: {0}", ex.Message);
context.Cancel(string.Format("Send to user notifications error: {0}", ex.Message), ex);
Logger.LogWarning(context.Reason);
}
}
else
{
try
{
var onlineClients = _hubContext.Clients.Users(identifiers.Select(x => x.UserId.ToString()));
var onlineClients = _hubContext.Clients.Users(context.Users.Select(x => x.UserId.ToString()));
Logger.LogDebug($"Found a singalr client, begin senging notifications");
await onlineClients.SendAsync(_options.MethodName, notification, cancellationToken);
await onlineClients.SendAsync(_options.MethodName, context.Notification, cancellationToken);
}
catch (Exception ex)
{
Logger.LogWarning("Could not send notifications to all users");
Logger.LogWarning("Send to user notifications error: {0}", ex.Message);
context.Cancel(string.Format("Send to user notifications error: {0}", ex.Message), ex);
Logger.LogWarning(context.Reason);
}
}
}

13
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Sms/LINGYUN/Abp/Notifications/Sms/SmsNotificationPublishProvider.cs

@ -16,22 +16,23 @@ public class SmsNotificationPublishProvider : NotificationPublishProvider
protected IOptions<AbpNotificationsSmsOptions> Options => ServiceProvider.LazyGetRequiredService<IOptions<AbpNotificationsSmsOptions>>();
protected override async Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
NotificationPublishContext context,
CancellationToken cancellationToken = default)
{
if (!identifiers.Any())
if (!context.Users.Any())
{
context.Cancel("The user who received the text message is empty.");
return;
}
var sendToPhones = await UserPhoneFinder.FindByUserIdsAsync(identifiers.Select(usr => usr.UserId), cancellationToken);
var sendToPhones = await UserPhoneFinder.FindByUserIdsAsync(context.Users.Select(usr => usr.UserId), cancellationToken);
if (!sendToPhones.Any())
{
context.Cancel("The user has not confirmed their mobile phone number, so the message cannot be sent.");
return;
}
await Sender.SendAsync(notification, sendToPhones.JoinAsString(","));
await Sender.SendAsync(context.Notification, sendToPhones.JoinAsString(","));
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
}

94
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.MiniProgram/LINGYUN/Abp/Notifications/WeChat/MiniProgram/WeChatMiniProgramNotificationPublishProvider.cs

@ -37,7 +37,7 @@ public class WeChatMiniProgramNotificationPublishProvider : NotificationPublishP
return true;
}
protected async override Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers, CancellationToken cancellationToken = default)
protected async override Task PublishAsync(NotificationPublishContext context, CancellationToken cancellationToken = default)
{
// step1 默认微信openid绑定的就是username,
// 如果不是,需要自行处理openid获取逻辑
@ -46,55 +46,51 @@ public class WeChatMiniProgramNotificationPublishProvider : NotificationPublishP
// 微信不支持推送到所有用户
// 在小程序里用户订阅消息后通过 api/subscribes/subscribe 接口订阅对应模板消息
foreach (var identifier in identifiers)
foreach (var identifier in context.Users)
{
await SendWeChatTemplateMessagAsync(notification, identifier, cancellationToken);
}
}
protected async virtual Task SendWeChatTemplateMessagAsync(NotificationInfo notification, UserIdentifier identifier, CancellationToken cancellationToken = default)
{
var templateId = GetOrDefaultTemplateId(notification.Data);
if (templateId.IsNullOrWhiteSpace())
{
Logger.LogWarning("Wechat weapp template id be empty, can not send notification!");
return;
}
Logger.LogDebug($"Get wechat weapp template id: {templateId}");
var redirect = GetOrDefault(notification.Data, "RedirectPage", null);
Logger.LogDebug($"Get wechat weapp redirect page: {redirect ?? "null"}");
var weAppState = GetOrDefault(notification.Data, "WeAppState", Options.Value.DefaultState);
Logger.LogDebug($"Get wechat weapp state: {weAppState ?? null}");
var weAppLang = GetOrDefault(notification.Data, "WeAppLanguage", Options.Value.DefaultLanguage);
Logger.LogDebug($"Get wechat weapp language: {weAppLang ?? null}");
// TODO: 如果微信端发布通知,请组装好 openid 字段在通知数据内容里面
var openId = GetOrDefault(notification.Data, AbpWeChatClaimTypes.OpenId, "");
if (openId.IsNullOrWhiteSpace())
{
// 发送小程序订阅消息
await SubscribeMessager
.SendAsync(
identifier.UserId, templateId, redirect, weAppLang,
weAppState, notification.Data.ExtraProperties, cancellationToken);
}
else
{
var weChatWeAppNotificationData = new SubscribeMessage(templateId, redirect, weAppState, weAppLang);
// 写入模板数据
weChatWeAppNotificationData.WriteData(notification.Data.ExtraProperties);
Logger.LogDebug($"Sending wechat weapp notification: {notification.Name}");
// 发送小程序订阅消息
await SubscribeMessager.SendAsync(weChatWeAppNotificationData, cancellationToken);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
var templateId = GetOrDefaultTemplateId(context.Notification.Data);
if (templateId.IsNullOrWhiteSpace())
{
context.Cancel("Wechat weapp template id be empty, can not send notification!");
Logger.LogWarning(context.Reason);
continue;
}
Logger.LogDebug($"Get wechat weapp template id: {templateId}");
var redirect = GetOrDefault(context.Notification.Data, "RedirectPage", null);
Logger.LogDebug($"Get wechat weapp redirect page: {redirect ?? "null"}");
var weAppState = GetOrDefault(context.Notification.Data, "WeAppState", Options.Value.DefaultState);
Logger.LogDebug($"Get wechat weapp state: {weAppState ?? null}");
var weAppLang = GetOrDefault(context.Notification.Data, "WeAppLanguage", Options.Value.DefaultLanguage);
Logger.LogDebug($"Get wechat weapp language: {weAppLang ?? null}");
// TODO: 如果微信端发布通知,请组装好 openid 字段在通知数据内容里面
var openId = GetOrDefault(context.Notification.Data, AbpWeChatClaimTypes.OpenId, "");
if (openId.IsNullOrWhiteSpace())
{
// 发送小程序订阅消息
await SubscribeMessager
.SendAsync(
identifier.UserId, templateId, redirect, weAppLang,
weAppState, context.Notification.Data.ExtraProperties, cancellationToken);
}
else
{
var weChatWeAppNotificationData = new SubscribeMessage(templateId, redirect, weAppState, weAppLang);
// 写入模板数据
weChatWeAppNotificationData.WriteData(context.Notification.Data.ExtraProperties);
Logger.LogDebug($"Sending wechat weapp notification: {context.Notification.Name}");
// 发送小程序订阅消息
await SubscribeMessager.SendAsync(weChatWeAppNotificationData, cancellationToken);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
}
}

30
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs

@ -41,34 +41,35 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider
}
protected async override Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
NotificationPublishContext context,
CancellationToken cancellationToken = default)
{
var sendToAgentIds = new List<string>();
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(notification.Name);
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(context.Notification.Name);
var agentId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.AgentId);
if (agentId.IsNullOrWhiteSpace())
{
Logger.LogWarning("Unable to send work weixin messages because agentId is not set.");
context.Cancel("Unable to send work weixin messages because agentId is not set.");
Logger.LogWarning(context.Reason);
return;
}
var notificationData = await NotificationDataSerializer.ToStandard(notification.Data);
var toTag = notification.Data.GetTagOrNull() ?? notificationDefine?.GetTagOrNull();
var toParty = notification.Data.GetPartyOrNull() ?? notificationDefine?.GetPartyOrNull();
var toUsers = await WeChatWorkInternalUserFinder.FindUserIdentifierListAsync(identifiers.Select(id => id.UserId));
var notificationData = await NotificationDataSerializer.ToStandard(context.Notification.Data);
var toTag = context.Notification.Data.GetTagOrNull() ?? notificationDefine?.GetTagOrNull();
var toParty = context.Notification.Data.GetPartyOrNull() ?? notificationDefine?.GetPartyOrNull();
var toUsers = await WeChatWorkInternalUserFinder.FindUserIdentifierListAsync(context.Users.Select(id => id.UserId));
if (toUsers.IsNullOrEmpty() && toTag.IsNullOrWhiteSpace() && toParty.IsNullOrWhiteSpace())
{
// touser、toparty、totag不能同时为空:https://developer.work.weixin.qq.com/document/path/90236
Logger.LogWarning("Unable to send work weixin messages because The recipient/department/label cannot be empty simultaneously.");
context.Cancel("Unable to send work weixin messages because The recipient/department/label cannot be empty simultaneously.");
Logger.LogWarning(context.Reason);
return;
}
// 发送到个人
await PublishToAgentAsync(
context,
agentId,
notification,
notificationData.Title,
notificationData.Message,
notificationData.Description,
@ -79,8 +80,8 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider
}
protected async virtual Task PublishToAgentAsync(
NotificationPublishContext context,
string agentId,
NotificationInfo notification,
string title,
string content,
string description = "",
@ -91,7 +92,7 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider
{
WeChatWorkMessage message = null;
switch (notification.ContentType)
switch (context.Notification.ContentType)
{
case NotificationContentType.Text:
message = new WeChatWorkTextMessage(agentId, new TextMessage(content));
@ -108,7 +109,8 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider
if (message == null)
{
Logger.LogWarning("Unable to send work weixin messages because WeChatWorkMessage is null.");
context.Cancel("Unable to send work weixin messages because WeChatWorkMessage is null.");
Logger.LogWarning(context.Reason);
return;
}
@ -118,6 +120,6 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider
await WeChatWorkMessageSender.SendAsync(message, cancellationToken);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
}

14
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WxPusher/LINGYUN/Abp/Notifications/WxPusher/WxPusherNotificationPublishProvider.cs

@ -2,7 +2,6 @@
using LINGYUN.Abp.WxPusher.Messages;
using LINGYUN.Abp.WxPusher.User;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -36,17 +35,16 @@ public class WxPusherNotificationPublishProvider : NotificationPublishProvider
}
protected async override Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
NotificationPublishContext context,
CancellationToken cancellationToken = default)
{
var subscribeUserIds = identifiers.Select(x => x.UserId);
var subscribeUserIds = context.Users.Select(x => x.UserId);
var topics = await WxPusherUserStore.GetSubscribeTopicsAsync(subscribeUserIds, cancellationToken);
var uids = await WxPusherUserStore.GetBindUidsAsync(subscribeUserIds, cancellationToken);
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(notification.Name);
var url = notification.Data.GetUrlOrNull() ?? notificationDefine?.GetUrlOrNull();
var notificationDefine = await NotificationDefinitionManager.GetOrNullAsync(context.Notification.Name);
var url = context.Notification.Data.GetUrlOrNull() ?? notificationDefine?.GetUrlOrNull();
var topicDefine = notificationDefine?.GetTopics();
if (topicDefine.Any())
{
@ -54,7 +52,7 @@ public class WxPusherNotificationPublishProvider : NotificationPublishProvider
}
var contentType = notificationDefine?.GetContentTypeOrDefault(MessageContentType.Text)
?? MessageContentType.Text;
var notificationData = await NotificationDataSerializer.ToStandard(notification.Data);
var notificationData = await NotificationDataSerializer.ToStandard(context.Notification.Data);
await WxPusherMessageSender.SendAsync(
content: notificationData.Message,
@ -65,6 +63,6 @@ public class WxPusherNotificationPublishProvider : NotificationPublishProvider
url: url,
cancellationToken: cancellationToken);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", notification.Name, Name);
Logger.LogDebug("The notification: {0} with provider: {1} has successfully published!", context.Notification.Name, Name);
}
}

14
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProvider.cs

@ -13,12 +13,16 @@ public interface INotificationPublishProvider
/// </summary>
string Name { get; }
/// <summary>
/// 是否可发布通知
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
Task<bool> CanPublishAsync(
NotificationInfo notification);
/// <summary>
/// 发布通知
/// </summary>
/// <param name="notification">通知信息</param>
/// <param name="identifiers">接收用户列表</param>
/// <param name="context">通知发送上下文信息</param>
/// <returns></returns>
Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers);
Task PublishAsync(NotificationPublishContext context);
}

4
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs

@ -7,6 +7,10 @@ namespace LINGYUN.Abp.Notifications;
public interface INotificationStore
{
Task InsertSendStateAsync(
NotificationSendInfo notificationSendInfo,
CancellationToken cancellationToken = default);
Task InsertUserSubscriptionAsync(
Guid? tenantId,
UserIdentifier identifier,

27
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs

@ -1,7 +1,6 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
@ -22,24 +21,23 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider
public ICancellationTokenProvider CancellationTokenProvider => ServiceProvider.LazyGetService<ICancellationTokenProvider>(NullCancellationTokenProvider.Instance);
public async Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
public async virtual Task<bool> CanPublishAsync(NotificationInfo notification)
{
return await CanPublishAsync(notification, GetCancellationToken());
}
public async Task PublishAsync(NotificationPublishContext context)
{
if (await CanPublishAsync(notification))
{
await PublishAsync(
notification,
identifiers,
GetCancellationToken());
}
await PublishAsync(context, GetCancellationToken());
}
protected virtual Task<bool> CanPublishAsync(
NotificationInfo notification,
NotificationInfo notification,
CancellationToken cancellationToken = default)
{
return Task.FromResult(true);
}
protected virtual CancellationToken GetCancellationToken(CancellationToken cancellationToken = default)
{
return CancellationTokenProvider.FallbackToProvider(cancellationToken);
@ -47,9 +45,8 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider
/// <summary>
/// 重写实现通知发布
/// </summary>
/// <param name="notification"></param>
/// <param name="identifiers"></param>
/// <param name="context">通知发送上下文</param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected abstract Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers, CancellationToken cancellationToken = default);
protected abstract Task PublishAsync(NotificationPublishContext context, CancellationToken cancellationToken = default);
}

7
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NullNotificationStore.cs

@ -11,6 +11,13 @@ public class NullNotificationStore : INotificationStore, ISingletonDependency
{
public readonly static INotificationStore Instance = new NullNotificationStore();
public Task InsertSendStateAsync(
NotificationSendInfo notificationSendInfo,
CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public Task ChangeUserNotificationReadStateAsync(
Guid? tenantId,
Guid userId,

68
aspnet-core/services/LY.MicroService.Applications.Single/BackgroundJobs/NotificationPublishJob.cs

@ -1,22 +1,28 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
namespace LY.MicroService.Applications.Single.BackgroundJobs;
public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobArgs>, ITransientDependency
{
protected IClock Clock { get; }
protected AbpNotificationsPublishOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected INotificationStore NotificationStore { get; }
protected INotificationDataSerializer NotificationDataSerializer { get; }
public NotificationPublishJob(
IClock clock,
IOptions<AbpNotificationsPublishOptions> options,
IServiceScopeFactory serviceScopeFactory,
INotificationStore notificationStore,
INotificationDataSerializer notificationDataSerializer)
{
Clock = clock;
Options = options.Value;
ServiceScopeFactory = serviceScopeFactory;
NotificationStore = notificationStore;
NotificationDataSerializer = notificationDataSerializer;
}
@ -31,8 +37,64 @@ public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobA
var notification = await store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId);
notification.Data = NotificationDataSerializer.Serialize(notification.Data);
await publishProvider.PublishAsync(notification, args.UserIdentifiers);
var sendInfo = OnPublishing(publishProvider, notification, args.UserIdentifiers);
try
{
if (await publishProvider.CanPublishAsync(notification))
{
var context = new NotificationPublishContext(notification, args.UserIdentifiers);
// 发布
await publishProvider.PublishAsync(context);
sendInfo.Sent(context.Exception);
if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
{
sendInfo.Cancel(context.Reason);
}
Logger.LogDebug($"Send notification {notification.Name} with provider {publishProvider.Name} was successful");
}
else
{
sendInfo.Disbaled();
}
await OnPublished(sendInfo);
}
catch (Exception ex)
{
Logger.LogWarning($"Send notification error with provider {publishProvider.Name}");
Logger.LogWarning($"Error message:{ex.Message}");
try
{
sendInfo.Sent(ex);
await OnPublished(sendInfo);
}
catch { }
throw;
}
}
}
}
protected virtual NotificationSendInfo OnPublishing(
INotificationPublishProvider provider,
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
{
return new NotificationSendInfo(
provider.Name,
Clock.Now,
notification,
identifiers);
}
protected async Task OnPublished(NotificationSendInfo sendInfo)
{
await NotificationStore.InsertSendStateAsync(sendInfo);
}
}

66
aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs

@ -13,6 +13,7 @@ using Volo.Abp.Json;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.TextTemplating;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace LY.MicroService.Applications.Single.EventBus.Distributed
@ -38,6 +39,10 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed
/// </summary>
protected AbpNotificationsPublishOptions Options { get; }
/// <summary>
/// Reference to <see cref="IClock"/>.
/// </summary>
protected IClock Clock { get; }
/// <summary>
/// Reference to <see cref="ICurrentTenant"/>.
/// </summary>
protected ICurrentTenant CurrentTenant { get; }
@ -90,6 +95,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed
/// Initializes a new instance of the <see cref="NotificationEventHandler"/> class.
/// </summary>
public NotificationEventHandler(
IClock clock,
ICurrentTenant currentTenant,
ITenantConfigurationCache tenantConfigurationCache,
IJsonSerializer jsonSerializer,
@ -104,6 +110,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed
INotificationSubscriptionManager notificationSubscriptionManager,
INotificationPublishProviderManager notificationPublishProviderManager)
{
Clock = clock;
Options = options.Value;
TenantConfigurationCache = tenantConfigurationCache;
CurrentTenant = currentTenant;
@ -414,29 +421,40 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed
/// </summary>
/// <param name="provider">通知发布者</param>
/// <param name="notificationInfo">通知信息</param>
/// <param name="subscriptionUserIdentifiers">订阅用户列表</param>
/// <param name="subscriptionUsers">订阅用户列表</param>
/// <returns></returns>
protected async Task PublishToSubscriberAsync(
INotificationPublishProvider provider,
NotificationInfo notificationInfo,
IEnumerable<UserIdentifier> subscriptionUsers)
{
var sendInfo = OnPublishing(provider, notificationInfo, subscriptionUsers);
try
{
Logger.LogDebug($"Sending notification with provider {provider.Name}");
// 2024-10-10: 框架层面应该取消通知数据转换,而是交给提供商来实现
//var notifacationDataMapping = Options.NotificationDataMappings
// .GetMapItemOrDefault(provider.Name, notificationInfo.Name);
//if (notifacationDataMapping != null)
//{
// notificationInfo.Data = notifacationDataMapping.MappingFunc(notificationInfo.Data);
//}
if (await provider.CanPublishAsync(notificationInfo))
{
var context = new NotificationPublishContext(notificationInfo, subscriptionUsers);
// 发布
await provider.PublishAsync(context);
sendInfo.Sent(context.Exception);
// 发布
await provider.PublishAsync(notificationInfo, subscriptionUsers);
if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
{
sendInfo.Cancel(context.Reason);
}
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
}
else
{
sendInfo.Disbaled();
}
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
await OnPublished(sendInfo);
}
catch (Exception ex)
{
@ -445,6 +463,13 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed
Logger.LogDebug($"Failed to send notification {notificationInfo.Name}. Try to push notification to background job");
// 发送失败的消息进入后台队列
await ProcessingFailedToQueueAsync(provider, notificationInfo, subscriptionUsers);
try
{
sendInfo.Sent(ex);
await OnPublished(sendInfo);
}
catch { }
}
}
/// <summary>
@ -472,10 +497,27 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed
subscriptionUsers.ToList(),
notificationInfo.TenantId));
}
catch(Exception ex)
catch (Exception ex)
{
Logger.LogWarning("Failed to push to background job, notification will be discarded, error cause: {message}", ex.Message);
}
}
protected virtual NotificationSendInfo OnPublishing(
INotificationPublishProvider provider,
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
{
return new NotificationSendInfo(
provider.Name,
Clock.Now,
notification,
identifiers);
}
protected async Task OnPublished(NotificationSendInfo sendInfo)
{
await NotificationStore.InsertSendStateAsync(sendInfo);
}
}
}

4
aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj

@ -28,7 +28,7 @@
<PackageReference Include="OpenIddict.Server.DataProtection" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Enrichers.Environment" />
<PackageReference Include="Serilog.Enrichers.Assembly" />
<PackageReference Include="Serilog.Enrichers.AssemblyName" />
<PackageReference Include="Serilog.Enrichers.Process" />
<PackageReference Include="Serilog.Enrichers.Thread" />
<PackageReference Include="Serilog.Settings.Configuration" />
@ -138,6 +138,8 @@
<ProjectReference Include="..\..\modules\account\LINGYUN.Abp.Account.HttpApi\LINGYUN.Abp.Account.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\account\LINGYUN.Abp.Account.Web.OAuth\LINGYUN.Abp.Account.Web.OAuth.csproj" />
<ProjectReference Include="..\..\modules\account\LINGYUN.Abp.Account.Web.OpenIddict\LINGYUN.Abp.Account.Web.OpenIddict.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.Application\LINGYUN.Abp.AIManagement.Application.csproj" />
<ProjectReference Include="..\..\modules\ai\LINGYUN.Abp.AIManagement.HttpApi\LINGYUN.Abp.AIManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\auditing\LINGYUN.Abp.Auditing.Application.Contracts\LINGYUN.Abp.Auditing.Application.Contracts.csproj" />
<ProjectReference Include="..\..\modules\auditing\LINGYUN.Abp.Auditing.Application\LINGYUN.Abp.Auditing.Application.csproj" />
<ProjectReference Include="..\..\modules\auditing\LINGYUN.Abp.Auditing.HttpApi\LINGYUN.Abp.Auditing.HttpApi.csproj" />

13
aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs

@ -1,3 +1,4 @@
using LINGYUN.Abp.AIManagement;
using Microsoft.AspNetCore.SignalR;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using VoloAbpExceptionHandlingOptions = Volo.Abp.AspNetCore.ExceptionHandling.AbpExceptionHandlingOptions;
@ -464,6 +465,18 @@ public partial class MicroServiceApplicationsSingleModule
}
}
private void ConfigureAIManagement(IConfiguration configuration)
{
if (configuration.GetValue<bool>("AIManagement:IsDynamicStoreEnabled"))
{
Configure<AIManagementOptions>(options =>
{
options.IsDynamicWorkspaceStoreEnabled = true;
options.SaveStaticWorkspacesToDatabase = true;
});
}
}
private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration)
{
var distributedLockEnabled = configuration["DistributedLock:IsEnabled"];

7
aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs

@ -1,3 +1,4 @@
using LINGYUN.Abp.AIManagement;
using LINGYUN.Abp.SystemInfo;
namespace LY.MicroService.Applications.Single;
@ -351,6 +352,11 @@ namespace LY.MicroService.Applications.Single;
// 微信模块 设置管理
typeof(AbpWeChatSettingManagementModule),
// AI管理模块 应用服务
typeof(AbpAIManagementApplicationModule),
// AI管理模块 控制器
typeof(AbpAIManagementHttpApiModule),
// 数据迁移模块
typeof(AbpDataDbMigratorModule),
// IP解析模块 IP2Region集成
@ -439,6 +445,7 @@ public partial class MicroServiceApplicationsSingleModule : AbpModule
ConfigureMultiTenancy(configuration);
ConfigureJsonSerializer(configuration);
ConfigureTextTemplating(configuration);
ConfigureAIManagement(configuration);
ConfigureFeatureManagement(configuration);
ConfigureSettingManagement(configuration);
ConfigureWebhooksManagement(configuration);

69
aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/BackgroundJobs/NotificationPublishJob.cs

@ -1,25 +1,34 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
namespace LY.MicroService.RealtimeMessage.BackgroundJobs;
public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobArgs>, ITransientDependency
{
protected IClock Clock { get; }
protected AbpNotificationsPublishOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected INotificationStore NotificationStore { get; }
protected INotificationDataSerializer NotificationDataSerializer { get; }
public NotificationPublishJob(
IClock clock,
IOptions<AbpNotificationsPublishOptions> options,
IServiceScopeFactory serviceScopeFactory,
INotificationStore notificationStore,
INotificationDataSerializer notificationDataSerializer)
{
Clock = clock;
Options = options.Value;
ServiceScopeFactory = serviceScopeFactory;
NotificationStore = notificationStore;
NotificationDataSerializer = notificationDataSerializer;
}
@ -33,9 +42,65 @@ public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobA
var store = scope.ServiceProvider.GetRequiredService<INotificationStore>();
var notification = await store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId);
notification.Data = NotificationDataSerializer.Serialize(notification.Data);
await publishProvider.PublishAsync(notification, args.UserIdentifiers);
var sendInfo = OnPublishing(publishProvider, notification, args.UserIdentifiers);
try
{
if (await publishProvider.CanPublishAsync(notification))
{
var context = new NotificationPublishContext(notification, args.UserIdentifiers);
// 发布
await publishProvider.PublishAsync(context);
sendInfo.Sent(context.Exception);
if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
{
sendInfo.Cancel(context.Reason);
}
Logger.LogDebug($"Send notification {notification.Name} with provider {publishProvider.Name} was successful");
}
else
{
sendInfo.Disbaled();
}
await OnPublished(sendInfo);
}
catch (Exception ex)
{
Logger.LogWarning($"Send notification error with provider {publishProvider.Name}");
Logger.LogWarning($"Error message:{ex.Message}");
try
{
sendInfo.Sent(ex);
await OnPublished(sendInfo);
}
catch { }
throw;
}
}
}
}
protected virtual NotificationSendInfo OnPublishing(
INotificationPublishProvider provider,
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
{
return new NotificationSendInfo(
provider.Name,
Clock.Now,
notification,
identifiers);
}
protected async Task OnPublished(NotificationSendInfo sendInfo)
{
await NotificationStore.InsertSendStateAsync(sendInfo);
}
}

59
aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs

@ -19,6 +19,7 @@ using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Settings;
using Volo.Abp.TextTemplating;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
@ -44,6 +45,10 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
/// </summary>
protected AbpNotificationsPublishOptions Options { get; }
/// <summary>
/// Reference to <see cref="IClock"/>.
/// </summary>
protected IClock Clock { get; }
/// <summary>
/// Reference to <see cref="ISettingProvider"/>.
/// </summary>
protected ISettingProvider SettingProvider { get; }
@ -100,6 +105,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
/// Initializes a new instance of the <see cref="NotificationEventHandler"/> class.
/// </summary>
public NotificationEventHandler(
IClock clock,
ICurrentTenant currentTenant,
ISettingProvider settingProvider,
ITenantConfigurationCache tenantConfigurationCache,
@ -115,6 +121,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
INotificationSubscriptionManager notificationSubscriptionManager,
INotificationPublishProviderManager notificationPublishProviderManager)
{
Clock = clock;
Options = options.Value;
TenantConfigurationCache = tenantConfigurationCache;
CurrentTenant = currentTenant;
@ -435,20 +442,40 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
/// </summary>
/// <param name="provider">通知发布者</param>
/// <param name="notificationInfo">通知信息</param>
/// <param name="subscriptionUserIdentifiers">订阅用户列表</param>
/// <param name="subscriptionUsers">订阅用户列表</param>
/// <returns></returns>
protected async Task PublishToSubscriberAsync(
INotificationPublishProvider provider,
NotificationInfo notificationInfo,
IEnumerable<UserIdentifier> subscriptionUsers)
{
var sendInfo = OnPublishing(provider, notificationInfo, subscriptionUsers);
try
{
Logger.LogDebug($"Sending notification with provider {provider.Name}");
// 发布
await provider.PublishAsync(notificationInfo, subscriptionUsers);
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
if (await provider.CanPublishAsync(notificationInfo))
{
var context = new NotificationPublishContext(notificationInfo, subscriptionUsers);
// 发布
await provider.PublishAsync(context);
sendInfo.Sent(context.Exception);
if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
{
sendInfo.Cancel(context.Reason);
}
Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
}
else
{
sendInfo.Disbaled();
}
await OnPublished(sendInfo);
}
catch (Exception ex)
{
@ -457,6 +484,13 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
Logger.LogDebug($"Failed to send notification {notificationInfo.Name}. Try to push notification to background job");
// 发送失败的消息进入后台队列
await ProcessingFailedToQueueAsync(provider, notificationInfo, subscriptionUsers);
try
{
sendInfo.Sent(ex);
await OnPublished(sendInfo);
}
catch { }
}
}
/// <summary>
@ -489,5 +523,22 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
Logger.LogWarning("Failed to push to background job, notification will be discarded, error cause: {message}", ex.Message);
}
}
protected virtual NotificationSendInfo OnPublishing(
INotificationPublishProvider provider,
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers)
{
return new NotificationSendInfo(
provider.Name,
Clock.Now,
notification,
identifiers);
}
protected async Task OnPublished(NotificationSendInfo sendInfo)
{
await NotificationStore.InsertSendStateAsync(sendInfo);
}
}
}

25
aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.PostgreSql.json

@ -0,0 +1,25 @@
{
"Quartz": {
"UsePersistentStore": true,
"Properties": {
"quartz.jobStore.dataSource": "tkm",
"quartz.jobStore.type": "Quartz.Impl.AdoJobStore.JobStoreTX,Quartz",
"quartz.jobStore.driverDelegateType": "Quartz.Impl.AdoJobStore.PostgreSQLDelegate,Quartz",
"quartz.dataSource.tkm.connectionString": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"quartz.dataSource.tkm.connectionStringName": "TaskManagement",
"quartz.dataSource.tkm.provider": "Npgsql",
"quartz.jobStore.clustered": "true",
"quartz.serializer.type": "json"
}
},
"ConnectionStrings": {
"Default": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpSaas": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpTenantManagement": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpSettingManagement": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpPermissionManagement": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpFeatureManagement": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpTextTemplating": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer",
"AbpLocalizationManagement": "Host=127.0.0.1;Database=Platform-V70;Username=postgres;Password=123456;SslMode=Prefer"
}
}
Loading…
Cancel
Save