Browse Source

Merge pull request #1109 from colinin/gdpr

feat: add Gdpr module
pull/1110/head
yx lin 1 year ago
committed by GitHub
parent
commit
9d2570b87d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 52
      aspnet-core/LINGYUN.MicroService.SingleProject.sln
  2. 6307
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250217124909_Add-Gdpr-Module.Designer.cs
  3. 77
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250217124909_Add-Gdpr-Module.cs
  4. 76
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs
  5. 2
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/RolePermissionDataSeedContributor.cs
  6. 5
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/LY.MicroService.Applications.Single.EntityFrameworkCore.csproj
  7. 10
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleDbMigrationEventHandler.cs
  8. 2
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsDbContext.cs
  9. 2
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs
  10. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/FodyWeavers.xml
  11. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/FodyWeavers.xsd
  12. 26
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN.Abp.Gdpr.Application.Contracts.csproj
  13. 14
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/AbpGdprApplicationContractsModule.cs
  14. 6
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/GdprRemoteServiceConsts.cs
  15. 11
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/GdprRequestDto.cs
  16. 9
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/GdprRequestGetListInput.cs
  17. 50
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/IGdprRequestAppService.cs
  18. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/FodyWeavers.xml
  19. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/FodyWeavers.xsd
  20. 28
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN.Abp.Gdpr.Application.csproj
  21. 26
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/AbpGdprApplicationModule.cs
  22. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/GdprApplicationMapperProfile.cs
  23. 12
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/GdprApplicationServiceBase.cs
  24. 211
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/GdprRequestAppService.cs
  25. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/FodyWeavers.xml
  26. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/FodyWeavers.xsd
  27. 27
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN.Abp.Gdpr.Domain.Identity.csproj
  28. 36
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprDomainIdentityModule.cs
  29. 25
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserAccountProvider.cs
  30. 67
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserDataProvider.cs
  31. 14
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/Localization/Resources/en.json
  32. 14
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/Localization/Resources/zh-Hans.json
  33. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/FodyWeavers.xml
  34. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/FodyWeavers.xsd
  35. 28
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN.Abp.Gdpr.Domain.Shared.csproj
  36. 38
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/AbpGdprDomainSharedModule.cs
  37. 14
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprErrorCodes.cs
  38. 17
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprInfoCacheItem.cs
  39. 6
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprInfoConsts.cs
  40. 33
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprRequestCacheItem.cs
  41. 12
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprUserAccountDeletionRequestedEto.cs
  42. 8
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/Localization/GdprResource.cs
  43. 31
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/Localization/Resources/en.json
  44. 31
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/Localization/Resources/zh-Hans.json
  45. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/FodyWeavers.xml
  46. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/FodyWeavers.xsd
  47. 26
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN.Abp.Gdpr.Domain.csproj
  48. 44
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/AbpCookieConsentOptions.cs
  49. 29
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/AbpGdprDomainModule.cs
  50. 40
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/AbpGdprOptions.cs
  51. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDbProterties.cs
  52. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDeleteUserAccountContext.cs
  53. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDeleteUserDataContext.cs
  54. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDomainMapperProfile.cs
  55. 43
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprInfo.cs
  56. 11
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprPrepareUserDataContext.cs
  57. 66
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprRequest.cs
  58. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserAccountProviderBase.cs
  59. 38
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserDataPreparedEventHandler.cs
  60. 33
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserDataProviderBase.cs
  61. 71
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserDataRequestedEventHandler.cs
  62. 26
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/IGdprRequestRepository.cs
  63. 19
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/IGdprUserAccountProvider.cs
  64. 24
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/IGdprUserDataProvider.cs
  65. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/FodyWeavers.xml
  66. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/FodyWeavers.xsd
  67. 25
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN.Abp.Gdpr.EntityFrameworkCore.csproj
  68. 22
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/AbpGdprEntityFrameworkCoreModule.cs
  69. 52
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/EfCoreGdprRequestRepository.cs
  70. 19
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/GdprDbContext.cs
  71. 54
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/GdprDbContextModelCreatingExtensions.cs
  72. 10
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/GdprModelBuilderConfigurationOptions.cs
  73. 11
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/IGdprDbContext.cs
  74. 3
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/FodyWeavers.xml
  75. 30
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/FodyWeavers.xsd
  76. 25
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/LINGYUN.Abp.Gdpr.HttpApi.csproj
  77. 41
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/LINGYUN/Abp/Gdpr/AbpGdprHttpApiModule.cs
  78. 69
      aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/LINGYUN/Abp/Gdpr/GdprRequestController.cs
  79. 1
      aspnet-core/services/LY.MicroService.Applications.Single/GlobalUsings.cs
  80. 8
      aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
  81. 13
      aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs

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

@ -630,6 +630,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Platform.HttpApi.Cl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Emailing.Platform", "modules\platform\LINGYUN.Abp.Emailing.Platform\LINGYUN.Abp.Emailing.Platform.csproj", "{9D357D4C-532A-4ADC-9CCB-C95B4E033547}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gdpr", "gdpr", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.Domain", "modules\gdpr\LINGYUN.Abp.Gdpr.Domain\LINGYUN.Abp.Gdpr.Domain.csproj", "{C33DBB02-F788-4EE0-ABDD-22861FC40D79}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.Domain.Shared", "modules\gdpr\LINGYUN.Abp.Gdpr.Domain.Shared\LINGYUN.Abp.Gdpr.Domain.Shared.csproj", "{E115487D-AAEF-4623-832B-94C14C79E991}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.Application.Contracts", "modules\gdpr\LINGYUN.Abp.Gdpr.Application.Contracts\LINGYUN.Abp.Gdpr.Application.Contracts.csproj", "{67B2403C-FFC8-47C7-BD71-A9D730430024}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.Application", "modules\gdpr\LINGYUN.Abp.Gdpr.Application\LINGYUN.Abp.Gdpr.Application.csproj", "{DA42E464-C824-461C-8D17-14FC2B293F65}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.HttpApi", "modules\gdpr\LINGYUN.Abp.Gdpr.HttpApi\LINGYUN.Abp.Gdpr.HttpApi.csproj", "{CDC0F589-D716-4FCE-9BBA-CD1A0B3D8409}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.EntityFrameworkCore", "modules\gdpr\LINGYUN.Abp.Gdpr.EntityFrameworkCore\LINGYUN.Abp.Gdpr.EntityFrameworkCore.csproj", "{57C95347-CF48-43DD-BFC9-597A43041AC5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Gdpr.Domain.Identity", "modules\gdpr\LINGYUN.Abp.Gdpr.Domain.Identity\LINGYUN.Abp.Gdpr.Domain.Identity.csproj", "{06FC3141-5F92-43A6-94C9-E2519EE9A91E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1664,6 +1680,34 @@ Global
{9D357D4C-532A-4ADC-9CCB-C95B4E033547}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D357D4C-532A-4ADC-9CCB-C95B4E033547}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D357D4C-532A-4ADC-9CCB-C95B4E033547}.Release|Any CPU.Build.0 = Release|Any CPU
{C33DBB02-F788-4EE0-ABDD-22861FC40D79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C33DBB02-F788-4EE0-ABDD-22861FC40D79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C33DBB02-F788-4EE0-ABDD-22861FC40D79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C33DBB02-F788-4EE0-ABDD-22861FC40D79}.Release|Any CPU.Build.0 = Release|Any CPU
{E115487D-AAEF-4623-832B-94C14C79E991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E115487D-AAEF-4623-832B-94C14C79E991}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E115487D-AAEF-4623-832B-94C14C79E991}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E115487D-AAEF-4623-832B-94C14C79E991}.Release|Any CPU.Build.0 = Release|Any CPU
{67B2403C-FFC8-47C7-BD71-A9D730430024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67B2403C-FFC8-47C7-BD71-A9D730430024}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67B2403C-FFC8-47C7-BD71-A9D730430024}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67B2403C-FFC8-47C7-BD71-A9D730430024}.Release|Any CPU.Build.0 = Release|Any CPU
{DA42E464-C824-461C-8D17-14FC2B293F65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA42E464-C824-461C-8D17-14FC2B293F65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA42E464-C824-461C-8D17-14FC2B293F65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA42E464-C824-461C-8D17-14FC2B293F65}.Release|Any CPU.Build.0 = Release|Any CPU
{CDC0F589-D716-4FCE-9BBA-CD1A0B3D8409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CDC0F589-D716-4FCE-9BBA-CD1A0B3D8409}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDC0F589-D716-4FCE-9BBA-CD1A0B3D8409}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CDC0F589-D716-4FCE-9BBA-CD1A0B3D8409}.Release|Any CPU.Build.0 = Release|Any CPU
{57C95347-CF48-43DD-BFC9-597A43041AC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57C95347-CF48-43DD-BFC9-597A43041AC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57C95347-CF48-43DD-BFC9-597A43041AC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57C95347-CF48-43DD-BFC9-597A43041AC5}.Release|Any CPU.Build.0 = Release|Any CPU
{06FC3141-5F92-43A6-94C9-E2519EE9A91E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06FC3141-5F92-43A6-94C9-E2519EE9A91E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06FC3141-5F92-43A6-94C9-E2519EE9A91E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06FC3141-5F92-43A6-94C9-E2519EE9A91E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1970,6 +2014,14 @@ Global
{A31C7F96-3AC6-44AF-B505-7D900C945291} = {F3449D35-8671-4BF6-8D1B-EFBB8AFD61DD}
{6C9E816F-3ECD-4AD1-A592-C4EDA1F011A3} = {F3449D35-8671-4BF6-8D1B-EFBB8AFD61DD}
{9D357D4C-532A-4ADC-9CCB-C95B4E033547} = {F3449D35-8671-4BF6-8D1B-EFBB8AFD61DD}
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {0B58AA48-665A-443F-A6A8-751FB9629DAF}
{C33DBB02-F788-4EE0-ABDD-22861FC40D79} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{E115487D-AAEF-4623-832B-94C14C79E991} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{67B2403C-FFC8-47C7-BD71-A9D730430024} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{DA42E464-C824-461C-8D17-14FC2B293F65} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{CDC0F589-D716-4FCE-9BBA-CD1A0B3D8409} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{57C95347-CF48-43DD-BFC9-597A43041AC5} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{06FC3141-5F92-43A6-94C9-E2519EE9A91E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}

6307
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250217124909_Add-Gdpr-Module.Designer.cs

File diff suppressed because it is too large

77
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250217124909_Add-Gdpr-Module.cs

@ -0,0 +1,77 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations
{
/// <inheritdoc />
public partial class AddGdprModule : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpGdprRequests",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
UserId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
ReadyTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
ExtraProperties = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AbpGdprRequests", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "AbpGdprInfos",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
RequestId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Data = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Provider = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_AbpGdprInfos", x => x.Id);
table.ForeignKey(
name: "FK_AbpGdprInfos_AbpGdprRequests_RequestId",
column: x => x.RequestId,
principalTable: "AbpGdprRequests",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_AbpGdprInfos_RequestId",
table: "AbpGdprInfos",
column: "RequestId");
migrationBuilder.CreateIndex(
name: "IX_AbpGdprRequests_UserId",
table: "AbpGdprRequests",
column: "UserId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpGdprInfos");
migrationBuilder.DropTable(
name: "AbpGdprRequests");
}
}
}

76
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs

@ -399,6 +399,68 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
b.ToTable("Demo_Books", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("Data")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("Data");
b.Property<string>("Provider")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("varchar(256)")
.HasColumnName("Provider");
b.Property<Guid>("RequestId")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("RequestId");
b.ToTable("AbpGdprInfos", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("varchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("ExtraProperties");
b.Property<DateTime>("ReadyTime")
.HasColumnType("datetime(6)");
b.Property<Guid>("UserId")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AbpGdprRequests", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b =>
{
b.Property<Guid>("Id")
@ -5737,6 +5799,15 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b =>
{
b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null)
.WithMany("Infos")
.HasForeignKey("RequestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b =>
{
b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition")
@ -6113,6 +6184,11 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
b.Navigation("Properties");
});
modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b =>
{
b.Navigation("Infos");
});
modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b =>
{
b.Navigation("ConnectionStrings");

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

@ -44,7 +44,7 @@ public class RolePermissionDataSeedContributor : IDataSeedContributor
await PermissionDataSeeder.SeedAsync(
RolePermissionValueProvider.ProviderName,
"users",
"Users",
new string[] { "Platform.Feedback.Create" },
context.TenantId);
}

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

@ -24,11 +24,12 @@
<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\data-protection\LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore\LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\demo\LINGYUN.Abp.Demo.EntityFrameworkCore\LINGYUN.Abp.Demo.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\data-protection\LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore\LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\demo\LINGYUN.Abp.Demo.EntityFrameworkCore\LINGYUN.Abp.Demo.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\gdpr\LINGYUN.Abp.Gdpr.EntityFrameworkCore\LINGYUN.Abp.Gdpr.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\realtime-message\LINGYUN.Abp.MessageService.EntityFrameworkCore\LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\realtime-notifications\LINGYUN.Abp.Notifications.EntityFrameworkCore\LINGYUN.Abp.Notifications.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\saas\LINGYUN.Abp.Saas.EntityFrameworkCore\LINGYUN.Abp.Saas.EntityFrameworkCore.csproj" />

10
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleDbMigrationEventHandler.cs

@ -8,6 +8,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Data;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EntityFrameworkCore.Migrations;
@ -48,7 +49,9 @@ public class SingleDbMigrationEventHandler :
IJobStore jobStore,
IJobScheduler jobScheduler,
IOptions<AbpBackgroundTasksOptions> options)
: base("SingleDbMigrator", currentTenant, unitOfWorkManager, tenantStore, abpDistributedLock, distributedEventBus, loggerFactory)
: base(
ConnectionStringNameAttribute.GetConnStringName<SingleMigrationsDbContext>(),
currentTenant, unitOfWorkManager, tenantStore, abpDistributedLock, distributedEventBus, loggerFactory)
{
GuidGenerator = guidGenerator;
IdentityUserManager = identityUserManager;
@ -76,11 +79,6 @@ public class SingleDbMigrationEventHandler :
protected async override Task AfterTenantCreated(TenantCreatedEto eventData, bool schemaMigrated)
{
if (!schemaMigrated)
{
return;
}
using (CurrentTenant.Change(eventData.Id))
{
await QueueBackgroundJobAsync(eventData);

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

@ -1,5 +1,6 @@
using LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore;
using LINGYUN.Abp.Demo.EntityFrameworkCore;
using LINGYUN.Abp.Gdpr.EntityFrameworkCore;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
using LINGYUN.Abp.MessageService.EntityFrameworkCore;
using LINGYUN.Abp.Notifications.EntityFrameworkCore;
@ -52,6 +53,7 @@ public class SingleMigrationsDbContext : AbpDbContext<SingleMigrationsDbContext>
modelBuilder.ConfigureMessageService();
modelBuilder.ConfigureDataProtectionManagement();
modelBuilder.ConfigureWebhooksManagement();
modelBuilder.ConfigureGdpr();
modelBuilder.ConfigureDemo();
}

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

@ -1,5 +1,6 @@
using LINGYUN.Abp.AuditLogging.EntityFrameworkCore;
using LINGYUN.Abp.Data.DbMigrator;
using LINGYUN.Abp.Gdpr.EntityFrameworkCore;
using LINGYUN.Abp.Identity.EntityFrameworkCore;
using LINGYUN.Abp.IdentityServer.EntityFrameworkCore;
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore;
@ -37,6 +38,7 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore;
typeof(AbpTextTemplatingEntityFrameworkCoreModule),
typeof(WebhooksManagementEntityFrameworkCoreModule),
typeof(TaskManagementEntityFrameworkCoreModule),
typeof(AbpGdprEntityFrameworkCoreModule),
typeof(AbpWeChatModule),
typeof(AbpDataDbMigratorModule)
)]

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

26
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN.Abp.Gdpr.Application.Contracts.csproj

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.Application.Contracts</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.Application.Contracts</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Authorization.Abstractions" />
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Domain.Shared\LINGYUN.Abp.Gdpr.Domain.Shared.csproj" />
</ItemGroup>
</Project>

14
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/AbpGdprApplicationContractsModule.cs

@ -0,0 +1,14 @@
using Volo.Abp.Application;
using Volo.Abp.Authorization;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Gdpr;
[DependsOn(
typeof(AbpAuthorizationAbstractionsModule),
typeof(AbpDddApplicationContractsModule),
typeof(AbpGdprDomainSharedModule)
)]
public class AbpGdprApplicationContractsModule : AbpModule
{
}

6
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/GdprRemoteServiceConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.Gdpr;
public static class GdprRemoteServiceConsts
{
public const string RemoteServiceName = "Gdpr";
public const string ModuleName = "gdpr";
}

11
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/GdprRequestDto.cs

@ -0,0 +1,11 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
namespace LINGYUN.Abp.Gdpr;
public class GdprRequestDto : EntityDto<Guid>, IHasCreationTime
{
public DateTime CreationTime { get; set; }
public DateTime ReadyTime { get; set; }
}

9
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/GdprRequestGetListInput.cs

@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.Gdpr;
public class GdprRequestGetListInput : PagedAndSortedResultRequestDto
{
public string? CreationTime { get; set; }
public string? ReadyTime { get; set; }
}

50
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application.Contracts/LINGYUN/Abp/Gdpr/IGdprRequestAppService.cs

@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace LINGYUN.Abp.Gdpr;
public interface IGdprRequestAppService : IApplicationService
{
/// <summary>
/// 获取个人数据请求详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<GdprRequestDto> GetAsync(Guid id);
/// <summary>
/// 获取个人数据请求列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<PagedResultDto<GdprRequestDto>> GetListAsync(GdprRequestGetListInput input);
/// <summary>
/// 下载已收集的用户数据
/// </summary>
/// <param name="requestId"></param>
/// <returns></returns>
Task<IRemoteStreamContent> DownloadPersonalDataAsync(Guid requestId);
/// <summary>
/// 删除个人数据请求
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task DeleteAsync(Guid id);
/// <summary>
/// 准备用户数据
/// </summary>
/// <returns></returns>
Task PreparePersonalDataAsync();
/// <summary>
/// 删除用户数据
/// </summary>
/// <returns></returns>
Task DeletePersonalDataAsync();
/// <summary>
/// 删除用户账户
/// </summary>
/// <returns></returns>
Task DeletePersonalAccountAsync();
}

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

28
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN.Abp.Gdpr.Application.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.Application</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.Application</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\exporter\LINGYUN.Abp.Exporter.Core\LINGYUN.Abp.Exporter.Core.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Application.Contracts\LINGYUN.Abp.Gdpr.Application.Contracts.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Domain\LINGYUN.Abp.Gdpr.Domain.csproj" />
</ItemGroup>
</Project>

26
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/AbpGdprApplicationModule.cs

@ -0,0 +1,26 @@
using LINGYUN.Abp.Exporter;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Gdpr;
[DependsOn(
typeof(AbpDddApplicationModule),
typeof(AbpGdprDomainModule),
typeof(AbpExporterCoreModule),
typeof(AbpGdprApplicationContractsModule)
)]
public class AbpGdprApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpGdprApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<AbpGdprApplicationModule>(validate: true);
});
}
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/GdprApplicationMapperProfile.cs

@ -0,0 +1,10 @@
using AutoMapper;
namespace LINGYUN.Abp.Gdpr;
public class GdprApplicationMapperProfile : Profile
{
public GdprApplicationMapperProfile()
{
CreateMap<GdprRequest, GdprRequestDto>();
}
}

12
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/GdprApplicationServiceBase.cs

@ -0,0 +1,12 @@
using LINGYUN.Abp.Gdpr.Localization;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.Gdpr;
public abstract class GdprApplicationServiceBase : ApplicationService
{
protected GdprApplicationServiceBase()
{
LocalizationResource = typeof(GdprResource);
ObjectMapperContext = typeof(AbpGdprApplicationModule);
}
}

211
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Application/LINGYUN/Abp/Gdpr/GdprRequestAppService.cs

@ -0,0 +1,211 @@
using LINGYUN.Abp.Exporter;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Caching;
using Volo.Abp.Content;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Gdpr;
using Volo.Abp.Json;
using Volo.Abp.Users;
namespace LINGYUN.Abp.Gdpr;
[Authorize]
public class GdprRequestAppService(
IJsonSerializer jsonSerializer,
IExporterProvider exporterProvider,
IOptions<AbpGdprOptions> gdprOptions,
IDistributedEventBus distributedEventBus,
IDistributedCache<GdprRequestCacheItem> gdprRequestCache,
IGdprRequestRepository gdprRequestRepository
) : GdprApplicationServiceBase,
IGdprRequestAppService
{
public async virtual Task DeleteAsync(Guid id)
{
var gdprRequest = await gdprRequestRepository.GetAsync(id);
await gdprRequestRepository.DeleteAsync(gdprRequest);
}
public async virtual Task DeletePersonalAccountAsync()
{
var userId = CurrentUser.GetId();
await DeletePersonalDataAsync();
await distributedEventBus.PublishAsync(
new GdprUserAccountDeletionRequestedEto()
{
UserId = userId,
});
}
public async virtual Task DeletePersonalDataAsync()
{
var userId = CurrentUser.GetId();
var specification = new Volo.Abp.Specifications.ExpressionSpecification<GdprRequest>(x => x.UserId == userId);
var totalCount = await gdprRequestRepository.GetCountAsync(specification);
var gdprRequests = await gdprRequestRepository.GetListAsync(specification, maxResultCount: totalCount);
await gdprRequestRepository.DeleteManyAsync(gdprRequests);
await CurrentUnitOfWork!.SaveChangesAsync();
await distributedEventBus.PublishAsync(
new GdprUserDataDeletionRequestedEto()
{
UserId = userId,
});
}
public async virtual Task<GdprRequestDto> GetAsync(Guid id)
{
var gdprRequest = await gdprRequestRepository.GetAsync(id);
return ObjectMapper.Map<GdprRequest, GdprRequestDto>(gdprRequest);
}
public async virtual Task<PagedResultDto<GdprRequestDto>> GetListAsync(GdprRequestGetListInput input)
{
Expression<Func<GdprRequest, bool>> expression = x => x.UserId == CurrentUser.GetId();
if (!input.CreationTime.IsNullOrWhiteSpace())
{
var times = input.CreationTime.Split(';');
if (times.Length >= 1 && DateTime.TryParse(times[0], out var beginCreationTime))
{
expression = expression.And(x => x.CreationTime >= beginCreationTime);
}
if (times.Length >= 2 && DateTime.TryParse(times[1], out var endCreationTime))
{
expression = expression.And(x => x.CreationTime <= endCreationTime);
}
}
if (!input.ReadyTime.IsNullOrWhiteSpace())
{
var times = input.ReadyTime.Split(';');
if (times.Length >= 1 && DateTime.TryParse(times[0], out var beginReadyTime))
{
expression = expression.And(x => x.ReadyTime >= beginReadyTime);
}
if (times.Length >= 2 && DateTime.TryParse(times[1], out var endReadyTime))
{
expression = expression.And(x => x.ReadyTime <= endReadyTime);
}
}
var specification = new Volo.Abp.Specifications.ExpressionSpecification<GdprRequest>(expression);
var totalCount = await gdprRequestRepository.GetCountAsync(specification);
var gdprRequests = await gdprRequestRepository.GetListAsync(specification,
input.Sorting, input.MaxResultCount, input.SkipCount);
return new PagedResultDto<GdprRequestDto>(totalCount,
ObjectMapper.Map<List<GdprRequest>, List<GdprRequestDto>>(gdprRequests));
}
public async virtual Task<IRemoteStreamContent> DownloadPersonalDataAsync(Guid requestId)
{
var userId = CurrentUser.GetId();
var cacheKey = GdprRequestCacheItem.CalculateCacheKey(userId, requestId);
var cacheItem = await gdprRequestCache.GetAsync(cacheKey);
if (cacheItem == null)
{
var gdprRequest = await gdprRequestRepository.GetAsync(requestId);
if (Clock.Now < gdprRequest.ReadyTime)
{
throw new BusinessException(GdprErrorCodes.DataNotPreparedYet)
.WithData(nameof(GdprRequest.ReadyTime), gdprRequest.ReadyTime.ToString("yyyy-MM-dd HH:mm:ss"));
}
cacheItem = new GdprRequestCacheItem(userId, requestId)
{
Infos = gdprRequest.Infos.Select(x => new GdprInfoCacheItem(x.Provider, x.Data)).ToList()
};
await gdprRequestCache.SetAsync(cacheKey, cacheItem, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = gdprOptions.Value.RequestTimeInterval
});
}
return await DownloadUserData(cacheItem);
}
public async virtual Task PreparePersonalDataAsync()
{
var userId = CurrentUser.GetId();
await ValidationRequestTimeInterval(userId);
var gdprRequest = new GdprRequest(
GuidGenerator.Create(),
userId,
Clock.Now.Add(gdprOptions.Value.MinutesForDataPreparation));
await gdprRequestRepository.InsertAsync(gdprRequest);
await CurrentUnitOfWork!.SaveChangesAsync();
await distributedEventBus.PublishAsync(
new GdprUserDataRequestedEto()
{
RequestId = gdprRequest.Id,
UserId = gdprRequest.UserId,
});
}
protected async virtual Task<IRemoteStreamContent> DownloadUserData(GdprRequestCacheItem cacheItem)
{
var fileName = $"{L["PersonalData"]}.xlsx";
var emptyValue = !L["PersonalData:Empty"].ResourceNotFound ? L["PersonalData:Empty"] : "None";
var personalData = new List<Dictionary<string, string>>();
foreach (var gdprInfo in cacheItem.Infos)
{
var gdprData = new Dictionary<string, string>();
var gdprInfoData = jsonSerializer.Deserialize<Dictionary<string, string>>(gdprInfo.Data);
foreach (var gdprDataItem in gdprInfoData)
{
// 导出数据本地化
var gdprDataKey = gdprDataItem.Key;
var gdprDataLocalizaztionKey = L[$"PersonalData:{gdprDataKey.ToPascalCase()}"];
if (!gdprDataLocalizaztionKey.ResourceNotFound)
{
gdprDataKey = gdprDataLocalizaztionKey.Value;
}
gdprData[gdprDataKey] = gdprDataItem.Value.IsNullOrWhiteSpace() ? emptyValue : gdprDataItem.Value;
}
personalData.Add(gdprData);
}
var stream = await exporterProvider.ExportAsync(personalData);
return new RemoteStreamContent(stream, fileName);
}
protected async Task ValidationRequestTimeInterval(Guid userId)
{
var latestRequestTime = await gdprRequestRepository.FindLatestRequestTimeAsync(userId);
if (latestRequestTime.HasValue && (Clock.Now - latestRequestTime) < gdprOptions.Value.RequestTimeInterval)
{
var nextRequestTime = latestRequestTime.Value.Add(gdprOptions.Value.RequestTimeInterval);
throw new BusinessException(GdprErrorCodes.PersonalDataRequestAlreadyDays)
.WithData(nameof(AbpGdprOptions.RequestTimeInterval), nextRequestTime.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

27
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN.Abp.Gdpr.Domain.Identity.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.Domain.Identity</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.Domain.Identity</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<None Remove="LINGYUN\Abp\Gdpr\Identity\Localization\Resources\*.json" />
<EmbeddedResource Include="LINGYUN\Abp\Gdpr\Identity\Localization\Resources\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\identity\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Domain\LINGYUN.Abp.Gdpr.Domain.csproj" />
</ItemGroup>
</Project>

36
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprDomainIdentityModule.cs

@ -0,0 +1,36 @@
using LINGYUN.Abp.Gdpr.Localization;
using LINGYUN.Abp.Identity;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.Gdpr.Identity;
[DependsOn(
typeof(AbpGdprDomainModule),
typeof(AbpIdentityDomainModule))]
public class AbpGdprDomainIdentityModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpGdprDomainIdentityModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<GdprResource>()
.AddVirtualJson("/LINGYUN/Abp/Gdpr/Identity/Localization/Resources");
});
Configure<AbpGdprOptions>(options =>
{
// 用户数据提供者
options.GdprUserDataProviders.Add(new AbpGdprIdentityUserDataProvider());
// 用户账户提供者
options.GdprUserAccountProviders.Add(new AbpGdprIdentityUserAccountProvider());
});
}
}

25
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserAccountProvider.cs

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.Identity;
namespace LINGYUN.Abp.Gdpr.Identity;
/// <summary>
/// 身份标识模块用户账户提供者
/// </summary>
public class AbpGdprIdentityUserAccountProvider : GdprUserAccountProviderBase
{
public const string ProviderName = "Identity";
public override string Name => ProviderName;
public async override Task DeleteAsync(GdprDeleteUserAccountContext context)
{
var identityUserManager = context.ServiceProvider.GetRequiredService<IdentityUserManager>();
var identityUser = await identityUserManager.GetByIdAsync(context.UserId);
(await identityUserManager.DeleteAsync(identityUser)).CheckErrors();
}
}

67
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/AbpGdprIdentityUserDataProvider.cs

@ -0,0 +1,67 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.ChangeTracking;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Gdpr;
using Volo.Abp.Identity;
using Volo.Abp.Users;
namespace LINGYUN.Abp.Gdpr.Identity;
/// <summary>
/// 身份标识模块用户数据提供者
/// </summary>
public class AbpGdprIdentityUserDataProvider: GdprUserDataProviderBase
{
public const string ProviderName = "Identity";
public override string Name => ProviderName;
public async override Task DeleteAsync(GdprDeleteUserDataContext context)
{
var identityUserRepository = context.ServiceProvider.GetRequiredService<IIdentityUserRepository>();
var identityUserManager = context.ServiceProvider.GetRequiredService<IdentityUserManager>();
var identityUser = await identityUserManager.GetByIdAsync(context.UserId);
identityUser.Name = "";
identityUser.Surname = "";
identityUser.SetIsActive(false);
await identityUserRepository.EnsureCollectionLoadedAsync(identityUser, u => u.Claims);
identityUser.Claims.Clear();
// TODO: 应设置为空字符串, 但是abp框架不允许Email为空
(await identityUserManager.SetEmailAsync(identityUser, $"{identityUser.UserName}@abp.io")).CheckErrors();
(await identityUserManager.SetPhoneNumberAsync(identityUser, "")).CheckErrors();
(await identityUserManager.UpdateAsync(identityUser)).CheckErrors();
}
[DisableEntityChangeTracking]
public async override Task PorepareAsync(GdprPrepareUserDataContext context)
{
var identityUserRepository = context.ServiceProvider.GetRequiredService<IIdentityUserRepository>();
var identityUser = await identityUserRepository.GetAsync(context.UserId);
var gdprDataInfo = new GdprDataInfo
{
{ nameof(UserData.UserName), identityUser.UserName },
{ nameof(UserData.Name), identityUser.Name },
{ nameof(UserData.Surname), identityUser.Surname },
{ nameof(UserData.Email), identityUser.Email },
{ nameof(UserData.PhoneNumber), identityUser.PhoneNumber },
{ nameof(IHasCreationTime.CreationTime), identityUser.CreationTime.ToString("yyyy-MM-dd HH:mm:ss") },
};
foreach (var identityUserClaim in identityUser.Claims)
{
gdprDataInfo.Add(identityUserClaim.ClaimType, identityUserClaim.ClaimValue);
}
await DispatchPrepareUserDataAsync(context, gdprDataInfo);
}
}

14
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/Localization/Resources/en.json

@ -0,0 +1,14 @@
{
"culture": "en",
"texts": {
"PersonalData:UserName": "User Name",
"PersonalData:Name": "Name",
"PersonalData:Surname": "Surname",
"PersonalData:Email": "Email",
"PersonalData:PhoneNumber": "Phone Number",
"PersonalData:CreationTime": "Registration Time",
"PersonalData:AvatarUrl": "Avatar",
"PersonalData:Picture": "Picture",
"PersonalData:Website": "Website"
}
}

14
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Identity/LINGYUN/Abp/Gdpr/Identity/Localization/Resources/zh-Hans.json

@ -0,0 +1,14 @@
{
"culture": "zh-Hans",
"texts": {
"PersonalData:UserName": "用户名",
"PersonalData:Name": "名称",
"PersonalData:Surname": "姓氏",
"PersonalData:Email": "邮件地址",
"PersonalData:PhoneNumber": "手机号",
"PersonalData:CreationTime": "注册时间",
"PersonalData:AvatarUrl": "头像",
"PersonalData:Picture": "头像",
"PersonalData:Website": "个人页"
}
}

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

28
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN.Abp.Gdpr.Domain.Shared.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.Domain.Shared</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.Domain.Shared</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<None Remove="LINGYUN\Abp\Gdpr\Localization\Resources\*.json" />
<EmbeddedResource Include="LINGYUN\Abp\Gdpr\Localization\Resources\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Features" />
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" />
<PackageReference Include="Volo.Abp.Gdpr.Abstractions" />
</ItemGroup>
</Project>

38
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/AbpGdprDomainSharedModule.cs

@ -0,0 +1,38 @@
using LINGYUN.Abp.Gdpr.Localization;
using Volo.Abp.Domain;
using Volo.Abp.Features;
using Volo.Abp.Gdpr;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.Gdpr;
[DependsOn(
typeof(AbpFeaturesModule),
typeof(AbpDddDomainSharedModule),
typeof(AbpGdprAbstractionsModule)
)]
public class AbpGdprDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpGdprDomainSharedModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<GdprResource>("en")
.AddVirtualJson("/LINGYUN/Abp/Gdpr/Localization/Resources");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace(GdprErrorCodes.Namespace, typeof(GdprResource));
});
}
}

14
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprErrorCodes.cs

@ -0,0 +1,14 @@
namespace LINGYUN.Abp.Gdpr;
public static class GdprErrorCodes
{
public const string Namespace = "Gdpr";
/// <summary>
/// 你已经提交了一个个人数据下载请求, 请在 {RequestTimeInterval} 后再次尝试.
/// </summary>
public const string PersonalDataRequestAlreadyDays = Namespace + ":010001";
/// <summary>
/// 你的个人数据正在准备中, 请在 {ReadyTime} 后再次尝试下载.
/// </summary>
public const string DataNotPreparedYet = Namespace + ":010002";
}

17
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprInfoCacheItem.cs

@ -0,0 +1,17 @@
namespace LINGYUN.Abp.Gdpr;
public class GdprInfoCacheItem
{
public string Data { get; set; }
public string Provider { get; set; }
public GdprInfoCacheItem()
{
}
public GdprInfoCacheItem(string provider, string data)
{
Data = data;
Provider = provider;
}
}

6
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprInfoConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.Gdpr;
public class GdprInfoConsts
{
public static int MaxProviderLength { get; set; } = 256;
}

33
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprRequestCacheItem.cs

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Gdpr;
[Serializable]
[IgnoreMultiTenancy]
public class GdprRequestCacheItem
{
private const string CacheKeyFormat = "uid:{0};rid:{1}";
public Guid UserId { get; set; }
public Guid RequestId { get; set; }
public List<GdprInfoCacheItem> Infos { get; set; }
public GdprRequestCacheItem()
{
Infos = new List<GdprInfoCacheItem>();
}
public GdprRequestCacheItem(Guid userId, Guid requestId)
{
UserId = userId;
RequestId = requestId;
Infos = new List<GdprInfoCacheItem>();
}
public static string CalculateCacheKey(Guid userId, Guid requestId)
{
return string.Format(CacheKeyFormat, userId, requestId);
}
}

12
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/GdprUserAccountDeletionRequestedEto.cs

@ -0,0 +1,12 @@
using System;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// 用户账户删除请求事件传输对象
/// </summary>
[Serializable]
public class GdprUserAccountDeletionRequestedEto
{
public Guid UserId { get; set; }
}

8
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/Localization/GdprResource.cs

@ -0,0 +1,8 @@
using Volo.Abp.Localization;
namespace LINGYUN.Abp.Gdpr.Localization;
[LocalizationResourceName("AbpGdpr")]
public class GdprResource
{
}

31
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/Localization/Resources/en.json

@ -0,0 +1,31 @@
{
"culture": "en",
"texts": {
"Gdpr:010001": "You have submitted a personal data download request, please try again after {RequestTimeInterval}.",
"Gdpr:010002": "Your personal data is being prepared, please try to download again after {ReadyTime}.",
"DisplayName:PersonalData": "Personal Data",
"DisplayName:Provider": "Provider",
"DisplayName:UserId": "User Id",
"DisplayName:CreationTime": "Creation Time",
"DisplayName:ReadyTime": "Ready Time",
"PersonalData:Empty": "None",
"Preparing": "Preparing",
"Download": "Download",
"RequestPersonalData": "Request Personal Data",
"DeletePersonalData": "Delete Personal Data",
"DeletePersonalAccount": "Delete Account",
"RequestedSuccessfully": "Requested Successfully",
"DeletePersonalAccountWarning": "This action will delete your account (including your personal data) and you will no longer be able to log in to the app!",
"PersonalAccountDeleteRequestReceived": "Your account deletion request is being processed and your personal data will be deleted at the end of the deletion process.",
"DeletePersonalDataWarning": "This action will delete your account personal data, and the deletion of some data may affect the page experience!",
"PersonalDataDeleteRequestReceived": "Your personal data deletion request is being processed, and you may need to log back into the app after the deletion process is complete.",
"PersonalDataPrepareRequestReceived": "Your personal data request is being processed and if the data is ready, you can download it on this page.",
"Accept": "Accept",
"PersonalData": "Personal Data",
"CookiePolicy": "Cookie Policy",
"PrivacyPolicy": "Privacy Policy",
"ThisWebsiteUsesCookie": "This website uses cookies to ensure you get the best experience on the website.",
"CookieConsentAgreePolicy": "If you continue to browse, then you agree to our {0}.",
"CookieConsentAgreePolicies": "If you continue to browse, then you agree to our {0} and {1}."
}
}

31
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain.Shared/LINGYUN/Abp/Gdpr/Localization/Resources/zh-Hans.json

@ -0,0 +1,31 @@
{
"culture": "zh-Hans",
"texts": {
"Gdpr:010001": "你已经提交了一个个人数据下载请求, 请在 {RequestTimeInterval} 后再次尝试.",
"Gdpr:010002": "你的个人数据正在准备中, 请在 {ReadyTime} 后再次尝试下载.",
"DisplayName:PersonalData": "个人数据",
"DisplayName:Provider": "收集模块",
"DisplayName:UserId": "用户Id",
"DisplayName:CreationTime": "请求时间",
"DisplayName:ReadyTime": "就绪时间",
"PersonalData:Empty": "无",
"Preparing": "准备中",
"Download": "下载",
"RequestPersonalData": "请求个人数据",
"DeletePersonalData": "删除个人数据",
"DeletePersonalAccount": "注销账号",
"RequestedSuccessfully": "请求成功",
"DeletePersonalAccountWarning": "此操作将会删除你的账户(包括你的个人数据), 并且你将不能再登录到应用程序!",
"PersonalAccountDeleteRequestReceived": "你的账户删除请求正在处理中, 在删除过程结束后,你的个人数据将被删除.",
"DeletePersonalDataWarning": "此操作将会删除你的账户个人数据, 某些数据被删除可能会影响页面体验!",
"PersonalDataDeleteRequestReceived": "你的个人数据删除请求正在处理中, 在删除过程结束后, 你可能需要重新登录应用程序.",
"PersonalDataPrepareRequestReceived": "你的个人数据请求正在处理中, 如果数据准备就绪, 你可以在这个页面下载它.",
"Accept": "接受",
"PersonalData": "个人数据",
"CookiePolicy": "Cookie政策",
"PrivacyPolicy": "隐私政策",
"ThisWebsiteUsesCookie": "本网站使用cookie以确保您在网站上获得最佳体验.",
"CookieConsentAgreePolicy": "如果您继续浏览, 即表示您同意我们的 {0}.",
"CookieConsentAgreePolicies": "如果您继续浏览, 则表示您同意我们的 {0} 和 {1}."
}
}

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

26
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN.Abp.Gdpr.Domain.csproj

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.Domain</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.Domain</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" />
<PackageReference Include="Volo.Abp.Ddd.Domain" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Domain.Shared\LINGYUN.Abp.Gdpr.Domain.Shared.csproj" />
</ItemGroup>
</Project>

44
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/AbpCookieConsentOptions.cs

@ -0,0 +1,44 @@
using System;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// AbpCookie同意选项
/// See: https://abp.io/docs/latest/modules/gdpr#abpcookieconsentoptions
/// </summary>
public class AbpCookieConsentOptions
{
/// <summary>
/// 启用或禁用Cookie Consent特征
/// </summary>
public bool IsEnabled { get; set; }
/// <summary>
/// 定义 Cookie 策略页面 URL.<br />
/// 设置后, "Cookie 策略"页面 URL 会自动添加到 Cookie 同意声明中.<br />
/// 因此, 用户可以在接受 cookie 同意之前检查 cookie 政策.<br />
/// 您可以将其设置为本地地址或完整 URL, 例如:<br />
/// /CookiePolicy<br />
/// https://example.com/cookie-policy
/// </summary>
public string CookiePolicyUrl { get; set; }
/// <summary>
/// 定义隐私政策页面 URL.<br />
/// 设置后, "隐私政策"页面 URL 会自动添加到 Cookie 同意声明中.<br />
/// 因此, 用户可以在接受 cookie 同意之前查看隐私政策.<br />
/// 您可以将其设置为本地地址或完整 URL, 例如:<br />
/// /PrivacyPolicy<br />
/// https://example.com/privacy-policy
/// </summary>
public string PrivacyPolicyUrl { get; set; }
/// <summary>
/// 定义 Cookie 同意的 Cookie 过期时间.<br />
/// 默认情况下, 当接受 Cookie 同意时, 它会将 Cookie 设置为有效期为 6 个月.
/// </summary>
public TimeSpan Expiration { get; set; }
public AbpCookieConsentOptions()
{
IsEnabled = true;
CookiePolicyUrl = "/CookiePolicy";
PrivacyPolicyUrl = "/PrivacyPolicy";
Expiration = TimeSpan.FromDays(180);
}
}

29
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/AbpGdprDomainModule.cs

@ -0,0 +1,29 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Gdpr;
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpDddDomainModule),
typeof(AbpGdprDomainSharedModule)
)]
public class AbpGdprDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpGdprOptions>(configuration.GetSection("Gdpr"));
Configure<AbpCookieConsentOptions>(configuration.GetSection("CookieConsent"));
context.Services.AddAutoMapperObjectMapper<AbpGdprDomainModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<AbpGdprDomainModule>(validate: true);
});
}
}

40
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/AbpGdprOptions.cs

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// AbpGdpr选项
/// See: https://abp.io/docs/latest/modules/gdpr#abpgdproptions
/// </summary>
public class AbpGdprOptions
{
/// <summary>
/// 用于指示允许的请求时间间隔.<br />
/// 如果要增加或减少个人数据请求间隔,可以配置此属性.<br />
/// 默认情况下, 用户可以每天请求一次其个人数据<br />
/// 默认值: 1 天
/// </summary>
public TimeSpan RequestTimeInterval { get; set; }
/// <summary>
/// 由于 GDPR 模块旨在支持分布式方案, 因此收集和准备个人数据应该需要一段时间.
/// 如果要根据应用程序的大小增加或减少数据准备时间, 可以配置此属性.<br />
/// 默认值: 60 分钟
/// </summary>
public TimeSpan MinutesForDataPreparation { get; set; }
/// <summary>
/// 用户数据提供者列表
/// </summary>
public IList<IGdprUserDataProvider> GdprUserDataProviders { get; }
/// <summary>
/// 用户账户提供者列表
/// </summary>
public IList<IGdprUserAccountProvider> GdprUserAccountProviders { get; }
public AbpGdprOptions()
{
RequestTimeInterval = TimeSpan.FromDays(1);
MinutesForDataPreparation = TimeSpan.FromMinutes(60);
GdprUserDataProviders = new List<IGdprUserDataProvider>();
GdprUserAccountProviders = new List<IGdprUserAccountProvider>();
}
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDbProterties.cs

@ -0,0 +1,10 @@
namespace LINGYUN.Abp.Gdpr;
public static class GdprDbProterties
{
public static string DbTablePrefix { get; set; } = "AbpGdpr";
public static string? DbSchema { get; set; } = null;
public const string ConnectionStringName = "AbpGdpr";
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDeleteUserAccountContext.cs

@ -0,0 +1,10 @@
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Gdpr;
namespace LINGYUN.Abp.Gdpr;
public class GdprDeleteUserAccountContext(IServiceProvider serviceProvider) : GdprUserDataProviderContext, IServiceProviderAccessor
{
public IServiceProvider ServiceProvider { get; } = serviceProvider;
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDeleteUserDataContext.cs

@ -0,0 +1,10 @@
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Gdpr;
namespace LINGYUN.Abp.Gdpr;
public class GdprDeleteUserDataContext(IServiceProvider serviceProvider) : GdprUserDataProviderContext, IServiceProviderAccessor
{
public IServiceProvider ServiceProvider { get; } = serviceProvider;
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprDomainMapperProfile.cs

@ -0,0 +1,10 @@
using AutoMapper;
namespace LINGYUN.Abp.Gdpr;
public class GdprDomainMapperProfile : Profile
{
public GdprDomainMapperProfile()
{
}
}

43
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprInfo.cs

@ -0,0 +1,43 @@
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// 表示用户的个人数据
/// See: https://abp.io/docs/latest/modules/gdpr#gdprinfo
/// </summary>
public class GdprInfo : Entity<Guid>
{
/// <summary>
/// GDPR 请求的 ID
/// </summary>
public virtual Guid RequestId { get; protected set; }
/// <summary>
/// 用于存储个人数据
/// </summary>
public virtual string Data { get; protected set; }
/// <summary>
/// 表示收集个人数据的模块
/// </summary>
public virtual string Provider { get; protected set; }
protected GdprInfo()
{
}
public GdprInfo(
Guid id,
Guid requestId,
string data,
string provider)
: base(id)
{
RequestId = requestId;
Data = Check.NotNullOrWhiteSpace(data, nameof(data));
Provider = Check.NotNullOrWhiteSpace(provider, nameof(provider), GdprInfoConsts.MaxProviderLength);
}
}

11
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprPrepareUserDataContext.cs

@ -0,0 +1,11 @@
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Gdpr;
namespace LINGYUN.Abp.Gdpr;
public class GdprPrepareUserDataContext(Guid requestId, IServiceProvider serviceProvider) : GdprUserDataProviderContext, IServiceProviderAccessor
{
public IServiceProvider ServiceProvider { get; } = serviceProvider;
public Guid RequestId { get; } = requestId;
}

66
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprRequest.cs

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Guids;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// 表示用户发出的 GDPR 请求
/// See: https://abp.io/docs/latest/modules/gdpr#gdprrequest
/// </summary>
public class GdprRequest : AggregateRoot<Guid>, IHasCreationTime
{
///// TODO: Abp Framework GDPR模块不支持多租户
///// <summary>
///// 租户Id
///// </summary>
///// public virtual Guid? TenantId { get; protected set; }
/// <summary>
/// 发出请求的用户的 ID
/// </summary>
public virtual Guid UserId { get; protected set; }
/// <summary>
/// 创建时间
/// </summary>
public virtual DateTime CreationTime { get; protected set; }
/// <summary>
/// 数据准备过程的结束时间
/// </summary>
public virtual DateTime ReadyTime { get; protected set; }
/// <summary>
/// 收集的用户个人数据
/// </summary>
public virtual ICollection<GdprInfo> Infos { get; protected set; }
protected GdprRequest()
{
Infos = new Collection<GdprInfo>();
}
public GdprRequest(
Guid id,
Guid userId,
DateTime readyTime)
: base(id)
{
UserId = userId;
ReadyTime = readyTime;
Infos = new Collection<GdprInfo>();
}
public void AddData(
IGuidGenerator guidGenerator,
string data,
string provider)
{
Infos.Add(
new GdprInfo(
guidGenerator.Create(),
Id,
data,
provider));
}
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserAccountProviderBase.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.Gdpr;
public abstract class GdprUserAccountProviderBase : IGdprUserAccountProvider
{
public abstract string Name { get; }
public abstract Task DeleteAsync(GdprDeleteUserAccountContext context);
}

38
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserDataPreparedEventHandler.cs

@ -0,0 +1,38 @@
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Gdpr;
using Volo.Abp.Guids;
using Volo.Abp.Json;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.Gdpr;
public class GdprUserDataPreparedEventHandler(
IGdprRequestRepository gdprRequestRepository,
IJsonSerializer jsonSerializer,
IGuidGenerator guidGenerator
): IDistributedEventHandler<GdprUserDataPreparedEto>,
ITransientDependency
{
[UnitOfWork]
public async virtual Task HandleEventAsync(GdprUserDataPreparedEto eventData)
{
if (eventData.Data.Any())
{
var gdprRequest = await gdprRequestRepository.FindAsync(eventData.RequestId);
if (gdprRequest != null)
{
var data = jsonSerializer.Serialize(eventData.Data);
gdprRequest.AddData(
guidGenerator,
data,
eventData.Provider);
await gdprRequestRepository.UpdateAsync(gdprRequest);
}
}
}
}

33
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserDataProviderBase.cs

@ -0,0 +1,33 @@
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Gdpr;
namespace LINGYUN.Abp.Gdpr;
public abstract class GdprUserDataProviderBase: IGdprUserDataProvider
{
public abstract string Name { get; }
public abstract Task DeleteAsync(GdprDeleteUserDataContext context);
public abstract Task PorepareAsync(GdprPrepareUserDataContext context);
/// <summary>
/// 发布个人数据
/// </summary>
/// <param name="context"></param>
/// <param name="gdprDataInfo">个人数据</param>
/// <returns></returns>
protected async virtual Task DispatchPrepareUserDataAsync(GdprPrepareUserDataContext context, GdprDataInfo gdprDataInfo)
{
var distributedEventBus = context.ServiceProvider.GetRequiredService<IDistributedEventBus>();
var gdprUserData = new GdprUserDataPreparedEto
{
RequestId = context.RequestId,
Provider = Name,
Data = gdprDataInfo,
};
await distributedEventBus.PublishAsync(gdprUserData);
}
}

71
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/GdprUserDataRequestedEventHandler.cs

@ -0,0 +1,71 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Gdpr;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// 用户个人数据收集事件监听器<br />
/// See: https://abp.io/docs/latest/modules/gdpr#gdpruserdatarequestedeto
/// </summary>
/// <param name="options"></param>
/// <param name="serviceScopeFactory"></param>
public class GdprUserDataRequestedEventHandler(
IOptions<AbpGdprOptions> options,
IServiceScopeFactory serviceScopeFactory
) : IDistributedEventHandler<GdprUserDataRequestedEto>,
IDistributedEventHandler<GdprUserDataDeletionRequestedEto>,
IDistributedEventHandler<GdprUserAccountDeletionRequestedEto>,
ITransientDependency
{
public async virtual Task HandleEventAsync(GdprUserDataRequestedEto eventData)
{
using var scope = serviceScopeFactory.CreateScope();
var context = new GdprPrepareUserDataContext(eventData.RequestId, scope.ServiceProvider)
{
UserId = eventData.UserId,
};
foreach (var gdprUserDataProvider in options.Value.GdprUserDataProviders)
{
await gdprUserDataProvider.PorepareAsync(context);
}
}
[UnitOfWork]
public async virtual Task HandleEventAsync(GdprUserDataDeletionRequestedEto eventData)
{
using var scope = serviceScopeFactory.CreateScope();
var context = new GdprDeleteUserDataContext(scope.ServiceProvider)
{
UserId = eventData.UserId,
};
foreach (var gdprUserDataProvider in options.Value.GdprUserDataProviders)
{
await gdprUserDataProvider.DeleteAsync(context);
}
}
[UnitOfWork]
public async virtual Task HandleEventAsync(GdprUserAccountDeletionRequestedEto eventData)
{
using var scope = serviceScopeFactory.CreateScope();
var context = new GdprDeleteUserAccountContext(scope.ServiceProvider)
{
UserId = eventData.UserId,
};
foreach (var gdprUserAccountProvider in options.Value.GdprUserAccountProviders)
{
await gdprUserAccountProvider.DeleteAsync(context);
}
}
}

26
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/IGdprRequestRepository.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace LINGYUN.Abp.Gdpr;
public interface IGdprRequestRepository : IBasicRepository<GdprRequest, Guid>
{
Task<DateTime?> FindLatestRequestTimeAsync(
Guid userId,
CancellationToken cancellationToken = default);
Task<int> GetCountAsync(
ISpecification<GdprRequest> specification,
CancellationToken cancellationToken = default);
Task<List<GdprRequest>> GetListAsync(
ISpecification<GdprRequest> specification,
string? sorting = $"{nameof(GdprRequest.CreationTime)} DESC",
int maxResultCount = 10,
int skipCount = 0,
CancellationToken cancellationToken = default);
}

19
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/IGdprUserAccountProvider.cs

@ -0,0 +1,19 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// 用户个人账户提供者
/// </summary>
public interface IGdprUserAccountProvider
{
/// <summary>
/// 提供者名称
/// </summary>
string Name { get; }
/// <summary>
/// 删除用户账户
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
Task DeleteAsync(GdprDeleteUserAccountContext context);
}

24
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.Domain/LINGYUN/Abp/Gdpr/IGdprUserDataProvider.cs

@ -0,0 +1,24 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.Gdpr;
/// <summary>
/// 用户个人数据提供者<br />
/// 实现: https://abp.io/docs/latest/modules/gdpr#gdpruserdatarequestedeto
/// </summary>
public interface IGdprUserDataProvider
{
/// <summary>
/// 提供者名称
/// </summary>
string Name { get; }
/// <summary>
/// 准备用户数据
/// </summary>
Task PorepareAsync(GdprPrepareUserDataContext context);
/// <summary>
/// 删除用户数据
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
Task DeleteAsync(GdprDeleteUserDataContext context);
}

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

25
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN.Abp.Gdpr.EntityFrameworkCore.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.EntityFrameworkCore</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.EntityFrameworkCore</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.EntityFrameworkCore" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Domain\LINGYUN.Abp.Gdpr.Domain.csproj" />
</ItemGroup>
</Project>

22
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/AbpGdprEntityFrameworkCoreModule.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Gdpr.EntityFrameworkCore;
[DependsOn(
typeof(AbpGdprDomainModule),
typeof(AbpEntityFrameworkCoreModule)
)]
public class AbpGdprEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<GdprDbContext>(options =>
{
options.AddRepository<GdprRequest, EfCoreGdprRequestRepository>();
options.AddDefaultRepositories<IGdprDbContext>();
});
}
}

52
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/EfCoreGdprRequestRepository.cs

@ -0,0 +1,52 @@
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.Gdpr.EntityFrameworkCore;
public class EfCoreGdprRequestRepository(IDbContextProvider<IGdprDbContext> dbContextProvider) :
EfCoreRepository<IGdprDbContext, GdprRequest, Guid>(dbContextProvider),
IGdprRequestRepository
{
public async virtual Task<DateTime?> FindLatestRequestTimeAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync())
.Where(x => x.UserId == userId)
.OrderByDescending(x => x.CreationTime)
.Select(x => x.CreationTime)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<int> GetCountAsync(ISpecification<GdprRequest> specification, CancellationToken cancellationToken = default)
{
return await (await GetQueryableAsync())
.Where(specification.ToExpression())
.CountAsync(GetCancellationToken(cancellationToken));
}
public async virtual Task<List<GdprRequest>> GetListAsync(
ISpecification<GdprRequest> specification,
string? sorting = $"{nameof(GdprRequest.CreationTime)} DESC",
int maxResultCount = 10,
int skipCount = 0,
CancellationToken cancellationToken = default)
{
return await(await GetQueryableAsync())
.Where(specification.ToExpression())
.OrderBy(sorting.IsNullOrWhiteSpace() ? $"{nameof(GdprRequest.CreationTime)} DESC" : sorting)
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async override Task<IQueryable<GdprRequest>> WithDetailsAsync()
{
return (await base.WithDetailsAsync()).Include(x => x.Infos);
}
}

19
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/GdprDbContext.cs

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.Gdpr.EntityFrameworkCore;
[ConnectionStringName(GdprDbProterties.ConnectionStringName)]
public class GdprDbContext(DbContextOptions<GdprDbContext> options) :
AbpDbContext<GdprDbContext>(options), IGdprDbContext
{
public virtual DbSet<GdprRequest> Requests { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ConfigureGdpr(); ;
}
}

54
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/GdprDbContextModelCreatingExtensions.cs

@ -0,0 +1,54 @@
using Microsoft.EntityFrameworkCore;
using System;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace LINGYUN.Abp.Gdpr.EntityFrameworkCore;
public static class GdprDbContextModelCreatingExtensions
{
public static void ConfigureGdpr(
this ModelBuilder builder,
Action<GdprModelBuilderConfigurationOptions>? optionsAction = null)
{
Check.NotNull(builder, nameof(builder));
var options = new GdprModelBuilderConfigurationOptions(
GdprDbProterties.DbTablePrefix,
GdprDbProterties.DbSchema
);
optionsAction?.Invoke(options);
builder.Entity<GdprRequest>(b =>
{
b.ToTable(options.TablePrefix + "Requests", options.Schema);
b.HasMany(p => p.Infos)
.WithOne()
.HasForeignKey(fk => fk.RequestId)
.IsRequired(true);
b.HasIndex(p => p.UserId);
b.ConfigureByConvention();
});
builder.Entity<GdprInfo>(b =>
{
b.ToTable(options.TablePrefix + "Infos", options.Schema);
b.Property(p => p.Provider)
.HasColumnName(nameof(GdprInfo.Provider))
.HasMaxLength(GdprInfoConsts.MaxProviderLength)
.IsRequired();
b.Property(p => p.Data)
.HasColumnName(nameof(GdprInfo.Data))
.IsRequired();
b.HasIndex(p => p.RequestId);
b.ConfigureByConvention();
});
builder.TryConfigureObjectExtensions<GdprDbContext>();
}
}

10
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/GdprModelBuilderConfigurationOptions.cs

@ -0,0 +1,10 @@
using JetBrains.Annotations;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace LINGYUN.Abp.Gdpr.EntityFrameworkCore;
public class GdprModelBuilderConfigurationOptions(
[NotNull] string tablePrefix = "",
[CanBeNull] string? schema = null) :
AbpModelBuilderConfigurationOptions(tablePrefix, schema)
{
}

11
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.EntityFrameworkCore/LINGYUN/Abp/Gdpr/EntityFrameworkCore/IGdprDbContext.cs

@ -0,0 +1,11 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.Gdpr.EntityFrameworkCore;
[ConnectionStringName(GdprDbProterties.ConnectionStringName)]
public interface IGdprDbContext : IEfCoreDbContext
{
DbSet<GdprRequest> Requests { get; }
}

3
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

25
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/LINGYUN.Abp.Gdpr.HttpApi.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.Gdpr.HttpApi</AssemblyName>
<PackageId>LINGYUN.Abp.Gdpr.HttpApi</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Nullable>enable</Nullable>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Application.Contracts\LINGYUN.Abp.Gdpr.Application.Contracts.csproj" />
</ItemGroup>
</Project>

41
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/LINGYUN/Abp/Gdpr/AbpGdprHttpApiModule.cs

@ -0,0 +1,41 @@
using LINGYUN.Abp.Gdpr.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Validation.Localization;
namespace LINGYUN.Abp.Gdpr;
[DependsOn(
typeof(AbpAspNetCoreMvcModule),
typeof(AbpGdprApplicationContractsModule)
)]
public class AbpGdprHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpGdprHttpApiModule).Assembly);
});
PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(
typeof(GdprResource),
typeof(AbpGdprApplicationContractsModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<GdprResource>()
.AddBaseTypes(typeof(AbpValidationResource));
});
}
}

69
aspnet-core/modules/gdpr/LINGYUN.Abp.Gdpr.HttpApi/LINGYUN/Abp/Gdpr/GdprRequestController.cs

@ -0,0 +1,69 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Content;
namespace LINGYUN.Abp.Gdpr;
[Authorize]
[Controller]
[Area(GdprRemoteServiceConsts.ModuleName)]
[RemoteService(Name = GdprRemoteServiceConsts.RemoteServiceName)]
[Route($"api/{GdprRemoteServiceConsts.ModuleName}/requests")]
public class GdprRequestController(
IGdprRequestAppService service
) : AbpControllerBase,
IGdprRequestAppService
{
[HttpDelete]
[Route("{id}")]
public virtual Task DeleteAsync(Guid id)
{
return service.DeleteAsync(id);
}
[HttpDelete]
[Route("personal-account")]
public virtual Task DeletePersonalAccountAsync()
{
return service.DeletePersonalAccountAsync();
}
[HttpDelete]
[Route("personal-data")]
public virtual Task DeletePersonalDataAsync()
{
return service.DeletePersonalDataAsync();
}
[HttpGet]
[Route("{id}")]
public virtual Task<GdprRequestDto> GetAsync(Guid id)
{
return service.GetAsync(id);
}
[HttpGet]
public virtual Task<PagedResultDto<GdprRequestDto>> GetListAsync(GdprRequestGetListInput input)
{
return service.GetListAsync(input);
}
[HttpGet]
[Route("personal-data/download/{requestId}")]
public virtual Task<IRemoteStreamContent> DownloadPersonalDataAsync(Guid requestId)
{
return service.DownloadPersonalDataAsync(requestId);
}
[HttpPost]
[Route("personal-data/prepare")]
public virtual Task PreparePersonalDataAsync()
{
return service.PreparePersonalDataAsync();
}
}

1
aspnet-core/services/LY.MicroService.Applications.Single/GlobalUsings.cs

@ -141,7 +141,6 @@ global using MiniExcelLibs.Attributes;
global using OpenIddict.Server;
global using OpenIddict.Server.AspNetCore;
global using Quartz;
global using Savorboard.CAP.InMemoryMessageQueue;
global using StackExchange.Redis;
global using System.Security.Cryptography;
global using System.Security.Cryptography.X509Certificates;

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

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\..\common.secrets.props" />
@ -16,7 +16,7 @@
<PackageReference Include="DotNetCore.CAP.RabbitMQ" />
<PackageReference Include="DotNetCore.CAP.OpenTelemetry" />
<PackageReference Include="DotNetCore.CAP.InMemoryStorage" />
<PackageReference Include="Savorboard.CAP.InMemoryMessageQueue" />
<PackageReference Include="DotNetCore.CAP.RedisStreams " />
<PackageReference Include="Elsa.Activities.Email" />
<PackageReference Include="Elsa.Activities.Http" />
<PackageReference Include="Elsa.Activities.UserTask" />
@ -155,6 +155,10 @@
<ProjectReference Include="..\..\modules\elsa\LINGYUN.Abp.Elsa\LINGYUN.Abp.Elsa.csproj" />
<ProjectReference Include="..\..\modules\feature-management\LINGYUN.Abp.FeatureManagement.Application\LINGYUN.Abp.FeatureManagement.Application.csproj" />
<ProjectReference Include="..\..\modules\feature-management\LINGYUN.Abp.FeatureManagement.HttpApi\LINGYUN.Abp.FeatureManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\gdpr\LINGYUN.Abp.Gdpr.Application\LINGYUN.Abp.Gdpr.Application.csproj" />
<ProjectReference Include="..\..\modules\gdpr\LINGYUN.Abp.Gdpr.Domain.Identity\LINGYUN.Abp.Gdpr.Domain.Identity.csproj" />
<ProjectReference Include="..\..\modules\gdpr\LINGYUN.Abp.Gdpr.EntityFrameworkCore\LINGYUN.Abp.Gdpr.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\modules\gdpr\LINGYUN.Abp.Gdpr.HttpApi\LINGYUN.Abp.Gdpr.HttpApi.csproj" />
<ProjectReference Include="..\..\modules\identityServer\LINGYUN.Abp.IdentityServer.Session\LINGYUN.Abp.IdentityServer.Session.csproj" />
<ProjectReference Include="..\..\modules\identity\LINGYUN.Abp.Identity.Application.Contracts\LINGYUN.Abp.Identity.Application.Contracts.csproj" />
<ProjectReference Include="..\..\modules\identity\LINGYUN.Abp.Identity.Application\LINGYUN.Abp.Identity.Application.csproj" />

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

@ -1,3 +1,7 @@
using LINGYUN.Abp.Gdpr;
using LINGYUN.Abp.Gdpr.EntityFrameworkCore;
using LINGYUN.Abp.Gdpr.Identity;
namespace LY.MicroService.Applications.Single;
[DependsOn(
@ -47,6 +51,15 @@ namespace LY.MicroService.Applications.Single;
// 身份认证模块 实体框架
typeof(AbpIdentityEntityFrameworkCoreModule),
// Gdpr 身份认证提供者模块
typeof(AbpGdprDomainIdentityModule),
// Gdpr 应用服务模块
typeof(AbpGdprApplicationModule),
// Gdpr 控制器模块
typeof(AbpGdprHttpApiModule),
// Gdpr 实体框架模块
typeof(AbpGdprEntityFrameworkCoreModule),
// 多语言管理模块 领域服务
typeof(AbpLocalizationManagementDomainModule),
// 多语言管理模块 应用服务

Loading…
Cancel
Save