Browse Source

Merge branch 'dev' into maliming/identity-pro-features-settings

pull/7719/head
maliming 6 years ago
parent
commit
381ba2f285
  1. 6
      docs/en/Best-Practices/Entity-Framework-Core-Integration.md
  2. 8
      docs/en/Customizing-Application-Modules-Overriding-Services.md
  3. 33
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs
  4. 6
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
  5. 30
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs
  6. 11
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs
  7. 2
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs
  8. 14
      framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs
  9. 2
      framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs
  10. 14
      framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProvider.cs
  11. 2
      framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProviderConfiguration.cs
  12. 1
      framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobContainerConfigurationExtensions.cs
  13. 12
      framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs
  14. 2
      framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs
  15. 59
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainer.cs
  16. 7
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactory.cs
  17. 15
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobNormalizeNaming.cs
  18. 64
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobNormalizeNamingService.cs
  19. 2
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobProviderBase.cs
  20. 11
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/IBlobNormalizeNamingService.cs
  21. 19
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/AbpCommonDbContextRegistrationOptions.cs
  22. 14
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/IAbpCommonDbContextRegistrationOptionsBuilder.cs
  23. 10
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs
  24. 30
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryRegistrarBase.cs
  25. 1
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
  26. 10
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs
  27. 143
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention_Tests.cs
  28. 10
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController_Tests.cs
  29. 12
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController.cs
  30. 19
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs
  31. 54
      framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs
  32. 2
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/IAuditLoggingDbContext.cs
  33. 10
      modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/IBloggingDbContext.cs
  34. 2018
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210225092130_Page_Remove_Description.Designer.cs
  35. 24
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210225092130_Page_Remove_Description.cs
  36. 4
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs
  37. 3
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs
  38. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs
  39. 3
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs
  40. 5
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs
  41. 2
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs
  42. 6
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Pages/Page.cs
  43. 1
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs
  44. 22
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs
  45. 9
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs
  46. 7
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PageAdminAppService_Tests.cs
  47. 4
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs
  48. 4
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs
  49. 4
      modules/cms-kit/test/Volo.CmsKit.TestBase/Pages/PageRepository_Test.cs
  50. 4
      modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs
  51. 6
      modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs
  52. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/IFeatureManagementDbContext.cs
  53. 12
      modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs
  54. 14
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs
  55. 14
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerServiceCollectionExtensions.cs
  56. 44
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpStrictRedirectUriValidator.cs
  57. 32
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs
  58. 74
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerCacheItemInvalidator.cs
  59. 141
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs
  60. 46
      modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs
  61. 69
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpStrictRedirectUriValidator_Tests.cs
  62. 138
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Cache/IdentityServerCacheItemInvalidator_Tests.cs
  63. 79
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/ResourceStore_Cache_Tests.cs
  64. 3
      modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs
  65. 2
      modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs
  66. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Application.Contracts/Volo/Abp/SettingManagement/SettingManagementPermissionDefinitionProvider.cs
  67. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Application.Contracts/Volo/Abp/SettingManagement/SettingManagementPermissions.cs
  68. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Application/Volo/Abp/SettingManagement/EmailSettingsAppService.cs
  69. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/AbpSettingManagementBlazorModule.cs
  70. 6
      modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Settings/EmailingPageContributor.cs
  71. 4
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/de-DE.json
  72. 4
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json
  73. 4
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/es.json
  74. 4
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/tr.json
  75. 4
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hans.json
  76. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/ISettingManagementDbContext.cs
  77. 2
      modules/setting-management/src/Volo.Abp.SettingManagement.Web/AbpSettingManagementWebModule.cs
  78. 6
      modules/setting-management/src/Volo.Abp.SettingManagement.Web/Settings/EmailingPageContributor.cs
  79. 4
      modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/ITenantManagementDbContext.cs
  80. 4
      npm/ng-packs/apps/dev-app/src/environments/environment.ts
  81. 68
      npm/ng-packs/packages/setting-management/config/src/components/email-setting-group/email-setting-group.component.html
  82. 60
      npm/ng-packs/packages/setting-management/config/src/components/email-setting-group/email-setting-group.component.ts
  83. 1
      npm/ng-packs/packages/setting-management/config/src/enums/index.ts
  84. 3
      npm/ng-packs/packages/setting-management/config/src/enums/setting-tab-names.ts
  85. 1
      npm/ng-packs/packages/setting-management/config/src/providers/index.ts
  86. 26
      npm/ng-packs/packages/setting-management/config/src/providers/setting-tab.provider.ts
  87. 17
      npm/ng-packs/packages/setting-management/config/src/proxy/README.md
  88. 27
      npm/ng-packs/packages/setting-management/config/src/proxy/email-settings.service.ts
  89. 4745
      npm/ng-packs/packages/setting-management/config/src/proxy/generate-proxy.json
  90. 2
      npm/ng-packs/packages/setting-management/config/src/proxy/index.ts
  91. 24
      npm/ng-packs/packages/setting-management/config/src/proxy/models.ts
  92. 2
      npm/ng-packs/packages/setting-management/config/src/public-api.ts
  93. 12
      npm/ng-packs/packages/setting-management/config/src/setting-management-config.module.ts
  94. 4
      npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts
  95. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs
  96. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs
  97. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs
  98. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
  99. 1
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs

6
docs/en/Best-Practices/Entity-Framework-Core-Integration.md

@ -16,11 +16,13 @@
[ConnectionStringName("AbpIdentity")]
public interface IIdentityDbContext : IEfCoreDbContext
{
DbSet<IdentityUser> Users { get; set; }
DbSet<IdentityRole> Roles { get; set; }
DbSet<IdentityUser> Users { get; }
DbSet<IdentityRole> Roles { get; }
}
````
* **Do not** define `set;` for the properties in this interface.
### DbContext class
* **Do** inherit the `DbContext` from the `AbpDbContext<TDbContext>` class.

8
docs/en/Customizing-Application-Modules-Overriding-Services.md

@ -196,12 +196,16 @@ This example replaces the `AccountController` (An API Controller defined in the
**`[ExposeServices(typeof(AccountController))]` is essential** here since it registers this controller for the `AccountController` in the dependency injection system. `[Dependency(ReplaceServices = true)]` is also recommended to clear the old registration (even the ASP.NET Core DI system selects the last registered one).
In addition, The `AccountController` will be removed from [`ApplicationModel`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationmodels.applicationmodel.controllers) because it defines `ExposeServicesAttribute`. If you don't want to remove it, you can configure `AbpAspNetCoreMvcOptions`:
In addition, the `MyAccountController` will be removed from [`ApplicationModel`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationmodels.applicationmodel.controllers) because it defines `ExposeServicesAttribute`.
If `IncludeSelf = true` is specified, i.e. `[ExposeServices(typeof(AccountController), IncludeSelf = true)]`, then `AccountController` will be removed instead. This is useful for **extending** a controller.
If you don't want to remove either controller, you can configure `AbpAspNetCoreMvcOptions`:
```csharp
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.IgnoredControllersOnModelExclusion.AddIfNotContains(typeof(AccountController));
options.IgnoredControllersOnModelExclusion.AddIfNotContains(typeof(MyAccountController));
});
```

33
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs

@ -73,7 +73,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
protected virtual void RemoveDuplicateControllers(ApplicationModel application)
{
var derivedControllerModels = new List<ControllerModel>();
var controllerModelsToRemove = new List<ControllerModel>();
foreach (var controllerModel in application.Controllers)
{
@ -87,19 +87,42 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
continue;
}
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf)
{
var exposedControllerModels = application.Controllers
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray();
controllerModelsToRemove.AddRange(exposedControllerModels);
Logger.LogInformation($"Removing the controller{(exposedControllerModels.Length > 1 ? "s" : "")} {exposeServicesAttr.ServiceTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")} from the application model since {(exposedControllerModels.Length > 1 ? "they are" : "it is")} replaced by the controller: {controllerModel.ControllerType.AssemblyQualifiedName}");
continue;
}
var baseControllerTypes = controllerModel.ControllerType
.GetBaseClasses(typeof(Controller), includeObject: false)
.Where(t => !t.IsAbstract)
.ToArray();
if (baseControllerTypes.Length > 0)
if (baseControllerTypes.Length == 0)
{
derivedControllerModels.Add(controllerModel);
Logger.LogInformation($"Removing the controller {controllerModel.ControllerType.AssemblyQualifiedName} from the application model since it replaces the controller(s): {baseControllerTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")}");
continue;
}
var baseControllerModels = application.Controllers
.Where(cm => baseControllerTypes.Contains(cm.ControllerType))
.ToArray();
if (baseControllerModels.Length == 0)
{
continue;
}
controllerModelsToRemove.Add(controllerModel);
Logger.LogInformation($"Removing the controller {controllerModel.ControllerType.AssemblyQualifiedName} from the application model since it replaces the controller(s): {baseControllerTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")}");
}
application.Controllers.RemoveAll(derivedControllerModels);
application.Controllers.RemoveAll(controllerModelsToRemove);
}
protected virtual void ConfigureRemoteService(ControllerModel controller, [CanBeNull] ConventionalControllerSetting configuration)

6
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs

@ -6,6 +6,7 @@ using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Security;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.AspNetCore.Tracing;
using Volo.Abp.AspNetCore.Uow;
@ -82,5 +83,10 @@ namespace Microsoft.AspNetCore.Builder
{
return app.UseMiddleware<AbpClaimsMapMiddleware>();
}
public static IApplicationBuilder UseAbpSecurityHeaders(this IApplicationBuilder app)
{
return app.UseMiddleware<AbpSecurityHeadersMiddleware>();
}
}
}

30
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs

@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Security
{
public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
/*X-Content-Type-Options header tells the browser to not try and “guess” what a mimetype of a resource might be, and to just take what mimetype the server has returned as fact.*/
AddHeaderIfNotExists(context, "X-Content-Type-Options", "nosniff");
/*X-XSS-Protection is a feature of Internet Explorer, Chrome and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks*/
AddHeaderIfNotExists(context, "X-XSS-Protection", "1; mode=block");
/*The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>. SAMEORIGIN makes it being displayed in a frame on the same origin as the page itself. The spec leaves it up to browser vendors to decide whether this option applies to the top level, the parent, or the whole chain*/
AddHeaderIfNotExists(context, "X-Frame-Options", "SAMEORIGIN");
await next.Invoke(context);
}
protected virtual void AddHeaderIfNotExists(HttpContext context, string key, string value)
{
context.Response.Headers.AddIfNotContains(new KeyValuePair<string, StringValues>(key, value));
}
}
}

11
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs

@ -10,13 +10,16 @@ namespace Volo.Abp.BlobStoring.Aliyun
{
protected IOssClientFactory OssClientFactory { get; }
protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; }
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
public AliyunBlobProvider(
IOssClientFactory ossClientFactory,
IAliyunBlobNameCalculator aliyunBlobNameCalculator)
IAliyunBlobNameCalculator aliyunBlobNameCalculator,
IBlobNormalizeNamingService blobNormalizeNamingService)
{
OssClientFactory = ossClientFactory;
AliyunBlobNameCalculator = aliyunBlobNameCalculator;
BlobNormalizeNamingService = blobNormalizeNamingService;
}
protected virtual IOss GetOssClient(BlobContainerConfiguration blobContainerConfiguration)
@ -88,15 +91,15 @@ namespace Volo.Abp.BlobStoring.Aliyun
return memoryStream;
}
private static string GetContainerName(BlobProviderArgs args)
protected virtual string GetContainerName(BlobProviderArgs args)
{
var configuration = args.Configuration.GetAliyunConfiguration();
return configuration.ContainerName.IsNullOrWhiteSpace()
? args.ContainerName
: configuration.ContainerName;
: BlobNormalizeNamingService.NormalizeContainerName(args.Configuration, configuration.ContainerName);
}
private bool BlobExists(IOss ossClient,string containerName, string blobName)
protected virtual bool BlobExists(IOss ossClient,string containerName, string blobName)
{
// Make sure Blob Container exists.
return ossClient.DoesBucketExist(containerName) &&

2
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs

@ -82,7 +82,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
public string ContainerName
{
get => _containerConfiguration.GetConfigurationOrDefault<string>(AliyunBlobProviderConfigurationNames.ContainerName);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.ContainerName, Check.NotNullOrWhiteSpace(value, nameof(value)));
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.ContainerName, value);
}
/// <summary>

14
framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs

@ -12,12 +12,16 @@ namespace Volo.Abp.BlobStoring.Aws
{
protected IAwsBlobNameCalculator AwsBlobNameCalculator { get; }
protected IAmazonS3ClientFactory AmazonS3ClientFactory { get; }
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
public AwsBlobProvider(IAwsBlobNameCalculator awsBlobNameCalculator,
IAmazonS3ClientFactory amazonS3ClientFactory)
public AwsBlobProvider(
IAwsBlobNameCalculator awsBlobNameCalculator,
IAmazonS3ClientFactory amazonS3ClientFactory,
IBlobNormalizeNamingService blobNormalizeNamingService)
{
AwsBlobNameCalculator = awsBlobNameCalculator;
AmazonS3ClientFactory = amazonS3ClientFactory;
BlobNormalizeNamingService = blobNormalizeNamingService;
}
public override async Task SaveAsync(BlobProviderSaveArgs args)
@ -111,7 +115,7 @@ namespace Volo.Abp.BlobStoring.Aws
return await AmazonS3ClientFactory.GetAmazonS3Client(configuration);
}
private async Task<bool> BlobExistsAsync(AmazonS3Client amazonS3Client, string containerName, string blobName)
protected virtual async Task<bool> BlobExistsAsync(AmazonS3Client amazonS3Client, string containerName, string blobName)
{
// Make sure Blob Container exists.
if (!await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, containerName))
@ -147,12 +151,12 @@ namespace Volo.Abp.BlobStoring.Aws
}
}
private static string GetContainerName(BlobProviderArgs args)
protected virtual string GetContainerName(BlobProviderArgs args)
{
var configuration = args.Configuration.GetAwsConfiguration();
return configuration.ContainerName.IsNullOrWhiteSpace()
? args.ContainerName
: configuration.ContainerName;
: BlobNormalizeNamingService.NormalizeContainerName(args.Configuration, configuration.ContainerName);
}
}
}

2
framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs

@ -82,7 +82,7 @@ namespace Volo.Abp.BlobStoring.Aws
public string ContainerName
{
get => _containerConfiguration.GetConfigurationOrDefault<string>(AwsBlobProviderConfigurationNames.ContainerName);
set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.ContainerName, Check.NotNullOrWhiteSpace(value, nameof(value)));
set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.ContainerName, value);
}
/// <summary>

14
framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProvider.cs

@ -9,10 +9,14 @@ namespace Volo.Abp.BlobStoring.Azure
public class AzureBlobProvider : BlobProviderBase, ITransientDependency
{
protected IAzureBlobNameCalculator AzureBlobNameCalculator { get; }
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
public AzureBlobProvider(IAzureBlobNameCalculator azureBlobNameCalculator)
public AzureBlobProvider(
IAzureBlobNameCalculator azureBlobNameCalculator,
IBlobNormalizeNamingService blobNormalizeNamingService)
{
AzureBlobNameCalculator = azureBlobNameCalculator;
BlobNormalizeNamingService = blobNormalizeNamingService;
}
public override async Task SaveAsync(BlobProviderSaveArgs args)
@ -87,22 +91,22 @@ namespace Volo.Abp.BlobStoring.Azure
await blobContainerClient.CreateIfNotExistsAsync();
}
private async Task<bool> BlobExistsAsync(BlobProviderArgs args, string blobName)
protected virtual async Task<bool> BlobExistsAsync(BlobProviderArgs args, string blobName)
{
// Make sure Blob Container exists.
return await ContainerExistsAsync(GetBlobContainerClient(args)) &&
(await GetBlobClient(args, blobName).ExistsAsync()).Value;
}
private static string GetContainerName(BlobProviderArgs args)
protected virtual string GetContainerName(BlobProviderArgs args)
{
var configuration = args.Configuration.GetAzureConfiguration();
return configuration.ContainerName.IsNullOrWhiteSpace()
? args.ContainerName
: configuration.ContainerName;
: BlobNormalizeNamingService.NormalizeContainerName(args.Configuration, configuration.ContainerName);
}
private static async Task<bool> ContainerExistsAsync(BlobContainerClient blobContainerClient)
protected virtual async Task<bool> ContainerExistsAsync(BlobContainerClient blobContainerClient)
{
return (await blobContainerClient.ExistsAsync()).Value;
}

2
framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProviderConfiguration.cs

@ -17,7 +17,7 @@
public string ContainerName
{
get => _containerConfiguration.GetConfigurationOrDefault<string>(AzureBlobProviderConfigurationNames.ContainerName);
set => _containerConfiguration.SetConfiguration(AzureBlobProviderConfigurationNames.ContainerName, Check.NotNullOrWhiteSpace(value, nameof(value)));
set => _containerConfiguration.SetConfiguration(AzureBlobProviderConfigurationNames.ContainerName, value);
}
/// <summary>

1
framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobContainerConfigurationExtensions.cs

@ -15,6 +15,7 @@ namespace Volo.Abp.BlobStoring.Minio
Action<MinioBlobProviderConfiguration> minioConfigureAction)
{
containerConfiguration.ProviderType = typeof(MinioBlobProvider);
containerConfiguration.NamingNormalizers.TryAdd<MinioBlobNamingNormalizer>();
minioConfigureAction(new MinioBlobProviderConfiguration(containerConfiguration));

12
framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs

@ -10,10 +10,14 @@ namespace Volo.Abp.BlobStoring.Minio
public class MinioBlobProvider : BlobProviderBase, ITransientDependency
{
protected IMinioBlobNameCalculator MinioBlobNameCalculator { get; }
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
public MinioBlobProvider(IMinioBlobNameCalculator minioBlobNameCalculator)
public MinioBlobProvider(
IMinioBlobNameCalculator minioBlobNameCalculator,
IBlobNormalizeNamingService blobNormalizeNamingService)
{
MinioBlobNameCalculator = minioBlobNameCalculator;
BlobNormalizeNamingService = blobNormalizeNamingService;
}
public override async Task SaveAsync(BlobProviderSaveArgs args)
@ -108,7 +112,7 @@ namespace Volo.Abp.BlobStoring.Minio
}
}
private async Task<bool> BlobExistsAsync(MinioClient client, string containerName , string blobName)
protected virtual async Task<bool> BlobExistsAsync(MinioClient client, string containerName , string blobName)
{
// Make sure Blob Container exists.
if (await client.BucketExistsAsync(containerName))
@ -133,13 +137,13 @@ namespace Volo.Abp.BlobStoring.Minio
return false;
}
private static string GetContainerName(BlobProviderArgs args)
protected virtual string GetContainerName(BlobProviderArgs args)
{
var configuration = args.Configuration.GetMinioConfiguration();
return configuration.BucketName.IsNullOrWhiteSpace()
? args.ContainerName
: configuration.BucketName;
: BlobNormalizeNamingService.NormalizeContainerName(args.Configuration, configuration.BucketName);
}
}
}

2
framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs

@ -5,7 +5,7 @@
public string BucketName
{
get => _containerConfiguration.GetConfigurationOrDefault<string>(MinioBlobProviderConfigurationNames.BucketName);
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value)));
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.BucketName, value);
}
/// <summary>

59
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainer.cs

@ -1,9 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
@ -88,12 +86,15 @@ namespace Volo.Abp.BlobStoring
protected IServiceProvider ServiceProvider { get; }
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
public BlobContainer(
string containerName,
BlobContainerConfiguration configuration,
IBlobProvider provider,
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider,
IBlobNormalizeNamingService blobNormalizeNamingService,
IServiceProvider serviceProvider)
{
ContainerName = containerName;
@ -101,6 +102,7 @@ namespace Volo.Abp.BlobStoring
Provider = provider;
CurrentTenant = currentTenant;
CancellationTokenProvider = cancellationTokenProvider;
BlobNormalizeNamingService = blobNormalizeNamingService;
ServiceProvider = serviceProvider;
}
@ -112,13 +114,13 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) = NormalizeNaming(ContainerName, name);
var blobNormalizeNaming = BlobNormalizeNamingService.NormalizeNaming(Configuration, ContainerName, name);
await Provider.SaveAsync(
new BlobProviderSaveArgs(
normalizedContainerName,
blobNormalizeNaming.ContainerName,
Configuration,
normalizedBlobName,
blobNormalizeNaming.BlobName,
stream,
overrideExisting,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
@ -133,14 +135,14 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) =
NormalizeNaming(ContainerName, name);
var blobNormalizeNaming =
BlobNormalizeNamingService.NormalizeNaming(Configuration, ContainerName, name);
return await Provider.DeleteAsync(
new BlobProviderDeleteArgs(
normalizedContainerName,
blobNormalizeNaming.ContainerName,
Configuration,
normalizedBlobName,
blobNormalizeNaming.BlobName,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
)
);
@ -153,14 +155,14 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) =
NormalizeNaming(ContainerName, name);
var blobNormalizeNaming =
BlobNormalizeNamingService.NormalizeNaming(Configuration, ContainerName, name);
return await Provider.ExistsAsync(
new BlobProviderExistsArgs(
normalizedContainerName,
blobNormalizeNaming.ContainerName,
Configuration,
normalizedBlobName,
blobNormalizeNaming.BlobName,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
)
);
@ -189,14 +191,14 @@ namespace Volo.Abp.BlobStoring
{
using (CurrentTenant.Change(GetTenantIdOrNull()))
{
var (normalizedContainerName, normalizedBlobName) =
NormalizeNaming(ContainerName, name);
var blobNormalizeNaming =
BlobNormalizeNamingService.NormalizeNaming(Configuration, ContainerName, name);
return await Provider.GetOrNullAsync(
new BlobProviderGetArgs(
normalizedContainerName,
blobNormalizeNaming.ContainerName,
Configuration,
normalizedBlobName,
blobNormalizeNaming.BlobName,
CancellationTokenProvider.FallbackToProvider(cancellationToken)
)
);
@ -212,28 +214,5 @@ namespace Volo.Abp.BlobStoring
return CurrentTenant.Id;
}
protected virtual (string, string) NormalizeNaming(string containerName, string blobName)
{
if (!Configuration.NamingNormalizers.Any())
{
return (containerName, blobName);
}
using (var scope = ServiceProvider.CreateScope())
{
foreach (var normalizerType in Configuration.NamingNormalizers)
{
var normalizer = scope.ServiceProvider
.GetRequiredService(normalizerType)
.As<IBlobNamingNormalizer>();
containerName = normalizer.NormalizeContainerName(containerName);
blobName = normalizer.NormalizeBlobName(blobName);
}
return (containerName, blobName);
}
}
}
}

7
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactory.cs

@ -17,18 +17,22 @@ namespace Volo.Abp.BlobStoring
protected IServiceProvider ServiceProvider { get; }
protected IBlobNormalizeNamingService BlobNormalizeNamingService { get; }
public BlobContainerFactory(
IBlobContainerConfigurationProvider configurationProvider,
ICurrentTenant currentTenant,
ICancellationTokenProvider cancellationTokenProvider,
IBlobProviderSelector providerSelector,
IServiceProvider serviceProvider)
IServiceProvider serviceProvider,
IBlobNormalizeNamingService blobNormalizeNamingService)
{
ConfigurationProvider = configurationProvider;
CurrentTenant = currentTenant;
CancellationTokenProvider = cancellationTokenProvider;
ProviderSelector = providerSelector;
ServiceProvider = serviceProvider;
BlobNormalizeNamingService = blobNormalizeNamingService;
}
public virtual IBlobContainer Create(string name)
@ -41,6 +45,7 @@ namespace Volo.Abp.BlobStoring
ProviderSelector.Get(name),
CurrentTenant,
CancellationTokenProvider,
BlobNormalizeNamingService,
ServiceProvider
);
}

15
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobNormalizeNaming.cs

@ -0,0 +1,15 @@
namespace Volo.Abp.BlobStoring
{
public class BlobNormalizeNaming
{
public string ContainerName { get; }
public string BlobName { get; }
public BlobNormalizeNaming(string containerName, string blobName)
{
ContainerName = containerName;
BlobName = blobName;
}
}
}

64
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobNormalizeNamingService.cs

@ -0,0 +1,64 @@
using System;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BlobStoring
{
public class BlobNormalizeNamingService : IBlobNormalizeNamingService, ITransientDependency
{
protected IServiceProvider ServiceProvider { get; }
public BlobNormalizeNamingService(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public BlobNormalizeNaming NormalizeNaming(
BlobContainerConfiguration configuration,
string containerName,
string blobName)
{
if (!configuration.NamingNormalizers.Any())
{
return new BlobNormalizeNaming(containerName, blobName);
}
using (var scope = ServiceProvider.CreateScope())
{
foreach (var normalizerType in configuration.NamingNormalizers)
{
var normalizer = scope.ServiceProvider
.GetRequiredService(normalizerType)
.As<IBlobNamingNormalizer>();
containerName = containerName.IsNullOrWhiteSpace()? containerName: normalizer.NormalizeContainerName(containerName);
blobName = blobName.IsNullOrWhiteSpace()? blobName: normalizer.NormalizeBlobName(blobName);
}
return new BlobNormalizeNaming(containerName, blobName);
}
}
public string NormalizeContainerName(BlobContainerConfiguration configuration, string containerName)
{
if (!configuration.NamingNormalizers.Any())
{
return containerName;
}
return NormalizeNaming(configuration, containerName, null).ContainerName;
}
public string NormalizeBlobName(BlobContainerConfiguration configuration, string blobName)
{
if (!configuration.NamingNormalizers.Any())
{
return blobName;
}
return NormalizeNaming(configuration, null, blobName).BlobName;
}
}
}

2
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobProviderBase.cs

@ -13,4 +13,4 @@ namespace Volo.Abp.BlobStoring
public abstract Task<Stream> GetOrNullAsync(BlobProviderGetArgs args);
}
}
}

11
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/IBlobNormalizeNamingService.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.BlobStoring
{
public interface IBlobNormalizeNamingService
{
BlobNormalizeNaming NormalizeNaming(BlobContainerConfiguration configuration, string containerName, string blobName);
string NormalizeContainerName(BlobContainerConfiguration configuration, string containerName);
string NormalizeBlobName(BlobContainerConfiguration configuration, string blobName);
}
}

19
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/AbpCommonDbContextRegistrationOptions.cs

@ -29,6 +29,8 @@ namespace Volo.Abp.DependencyInjection
public Dictionary<Type, Type> CustomRepositories { get; }
public List<Type> SpecifiedDefaultRepositories { get; }
public bool SpecifiedDefaultRepositoryTypes => DefaultRepositoryImplementationType != null && DefaultRepositoryImplementationTypeWithoutKey != null;
protected AbpCommonDbContextRegistrationOptions(Type originalDbContextType, IServiceCollection services)
@ -38,6 +40,7 @@ namespace Volo.Abp.DependencyInjection
DefaultRepositoryDbContextType = originalDbContextType;
CustomRepositories = new Dictionary<Type, Type>();
ReplacedDbContextTypes = new List<Type>();
SpecifiedDefaultRepositories = new List<Type>();
}
public IAbpCommonDbContextRegistrationOptionsBuilder ReplaceDbContext<TOtherDbContext>()
@ -82,6 +85,20 @@ namespace Volo.Abp.DependencyInjection
return AddDefaultRepositories(typeof(TDefaultRepositoryDbContext), includeAllEntities);
}
public IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepository<TEntity>()
{
return AddDefaultRepository(typeof(TEntity));
}
public IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepository(Type entityType)
{
EntityHelper.CheckEntity(entityType);
SpecifiedDefaultRepositories.AddIfNotContains(entityType);
return this;
}
public IAbpCommonDbContextRegistrationOptionsBuilder AddRepository<TEntity, TRepository>()
{
AddCustomRepository(typeof(TEntity), typeof(TRepository));
@ -118,4 +135,4 @@ namespace Volo.Abp.DependencyInjection
CustomRepositories[entityType] = repositoryType;
}
}
}
}

14
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/IAbpCommonDbContextRegistrationOptionsBuilder.cs

@ -39,6 +39,20 @@ namespace Volo.Abp.DependencyInjection
/// </param>
IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepositories(Type defaultRepositoryDbContextType, bool includeAllEntities = false);
/// <summary>
/// Registers custom repository for a specific entity.
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepository<TEntity>();
/// <summary>
/// Registers default repository for a specific entity.
/// </summary>
/// <param name="entityType"></param>
/// <returns></returns>
IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepository(Type entityType);
/// <summary>
/// Registers custom repository for a specific entity.
/// Custom repositories overrides default repositories.

10
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs

@ -118,9 +118,19 @@ namespace Volo.Abp.Domain.Entities
public static bool IsEntity([NotNull] Type type)
{
Check.NotNull(type, nameof(type));
return typeof(IEntity).IsAssignableFrom(type);
}
public static void CheckEntity([NotNull] Type type)
{
Check.NotNull(type, nameof(type));
if (!IsEntity(type))
{
throw new AbpException($"Given {nameof(type)} is not an entity: {type.AssemblyQualifiedName}. It must implement {typeof(IEntity).AssemblyQualifiedName}.");
}
}
public static bool IsEntityWithId([NotNull] Type type)
{
foreach (var interfaceType in type.GetInterfaces())

30
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryRegistrarBase.cs

@ -17,20 +17,27 @@ namespace Volo.Abp.Domain.Repositories
}
public virtual void AddRepositories()
{
RegisterCustomRepositories();
RegisterDefaultRepositories();
RegisterSpecifiedDefaultRepositories();
}
protected virtual void RegisterCustomRepositories()
{
foreach (var customRepository in Options.CustomRepositories)
{
Options.Services.AddDefaultRepository(customRepository.Key, customRepository.Value, replaceExisting: true);
}
if (Options.RegisterDefaultRepositories)
{
RegisterDefaultRepositories();
}
}
protected virtual void RegisterDefaultRepositories()
{
if (!Options.RegisterDefaultRepositories)
{
return;
}
foreach (var entityType in GetEntityTypes(Options.OriginalDbContextType))
{
if (!ShouldRegisterDefaultRepositoryFor(entityType))
@ -42,6 +49,17 @@ namespace Volo.Abp.Domain.Repositories
}
}
protected virtual void RegisterSpecifiedDefaultRepositories()
{
foreach (var entityType in Options.SpecifiedDefaultRepositories)
{
if (!Options.CustomRepositories.ContainsKey(entityType))
{
RegisterDefaultRepository(entityType);
}
}
}
protected virtual void RegisterDefaultRepository(Type entityType)
{
Options.Services.AddDefaultRepository(
@ -92,4 +110,4 @@ namespace Volo.Abp.Domain.Repositories
protected abstract Type GetRepositoryType(Type dbContextType, Type entityType, Type primaryKeyType);
}
}
}

1
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs

@ -110,6 +110,7 @@ namespace Volo.Abp.AspNetCore.Mvc
app.UseCorrelationId();
app.UseVirtualFiles();
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
app.UseRouting();
app.UseMiddleware<FakeAuthenticationMiddleware>();
app.UseAbpClaimsMap();

10
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/AuthTestController_Tests.cs

@ -2,21 +2,11 @@
using System.Security.Claims;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.AspNetCore.TestBase;
using Volo.Abp.Autofac;
using Volo.Abp.MemoryDb;
using Volo.Abp.Modularity;
using Volo.Abp.Security.Claims;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Authorization
{
[DependsOn(
typeof(AbpAspNetCoreTestBaseModule),
typeof(AbpMemoryDbTestModule),
typeof(AbpAspNetCoreMvcModule),
typeof(AbpAutofacModule)
)]
public class AuthTestController_Tests : AspNetCoreMvcTestBase
{
private readonly FakeUserClaims _fakeRequiredService;

143
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention_Tests.cs

@ -0,0 +1,143 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Shouldly;
using System;
using System.Reflection;
using Volo.Abp.DependencyInjection;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Conventions
{
public class AbpServiceConvention_Tests : AspNetCoreMvcTestBase
{
private readonly IConventionalRouteBuilder _conventionalRouteBuilder;
private readonly IOptions<AbpAspNetCoreMvcOptions> _options;
public AbpServiceConvention_Tests()
{
_conventionalRouteBuilder = GetRequiredService<IConventionalRouteBuilder>();
_options = GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
}
[Fact]
public void Should_Not_Remove_Derived_Controller_If_Not_Expose_Service()
{
// Arrange
var applicationModel = new ApplicationModel();
var baseControllerModel = new ControllerModel(typeof(BaseController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(baseControllerModel);
var derivedControllerModel = new ControllerModel(typeof(DerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldContain(baseControllerModel);
applicationModel.Controllers.ShouldContain(derivedControllerModel);
}
[Fact]
public void Should_Remove_Exposed_Controller_If_Expose_Self()
{
// Arrange
var applicationModel = new ApplicationModel();
var baseControllerModel = new ControllerModel(typeof(BaseController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(baseControllerModel);
var derivedControllerModel = new ControllerModel(typeof(ExposeServiceIncludeSelfDerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldNotContain(baseControllerModel);
applicationModel.Controllers.ShouldContain(derivedControllerModel);
}
[Fact]
public void Should_Not_Remove_Derived_Controller_If_No_Base_Controller_Model()
{
// Arrange
var applicationModel = new ApplicationModel();
var derivedControllerModel = new ControllerModel(typeof(ExposeServiceDerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldContain(derivedControllerModel);
}
[Fact]
public void Should_Remove_Derived_Controller_If_Expose_Service()
{
// Arrange
var applicationModel = new ApplicationModel();
var baseControllerModel = new ControllerModel(typeof(BaseController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(baseControllerModel);
var derivedControllerModel = new ControllerModel(typeof(ExposeServiceDerivedController).GetTypeInfo(), Array.Empty<object>())
{
Application = applicationModel
};
applicationModel.Controllers.Add(derivedControllerModel);
var abpServiceConvention = new AbpServiceConvention(_options, _conventionalRouteBuilder);
// Act
abpServiceConvention.Apply(applicationModel);
// Assert
applicationModel.Controllers.ShouldContain(baseControllerModel);
applicationModel.Controllers.ShouldNotContain(derivedControllerModel);
}
}
public class BaseController : Controller
{
}
public class DerivedController : BaseController
{
}
[ExposeServices(typeof(BaseController))]
public class ExposeServiceDerivedController : BaseController
{
}
[ExposeServices(typeof(BaseController), IncludeSelf = true)]
public class ExposeServiceIncludeSelfDerivedController : BaseController
{
}
}

10
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController_Tests.cs

@ -2,20 +2,10 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.AspNetCore.Mvc.Authorization;
using Volo.Abp.AspNetCore.TestBase;
using Volo.Abp.Autofac;
using Volo.Abp.MemoryDb;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Security.Claims
{
[DependsOn(
typeof(AbpAspNetCoreTestBaseModule),
typeof(AbpMemoryDbTestModule),
typeof(AbpAspNetCoreMvcModule),
typeof(AbpAutofacModule)
)]
public class ClaimsMapTestController_Tests : AspNetCoreMvcTestBase
{
private readonly FakeUserClaims _fakeRequiredService;

12
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController.cs

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
namespace Volo.Abp.AspNetCore.Mvc.Security.Headers
{
public class SecurityHeadersTestController : AbpController
{
public ActionResult Get()
{
return Content("OK");
}
}
}

19
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs

@ -0,0 +1,19 @@
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Security.Headers
{
public class SecurityHeadersTestController_Tests : AspNetCoreMvcTestBase
{
[Fact]
public async Task SecurityHeaders_Should_Be_Added()
{
var responseMessage = await GetResponseAsync("/SecurityHeadersTest/Get");
responseMessage.Headers.ShouldContain(x => x.Key == "X-Content-Type-Options" & x.Value.First().ToString() == "nosniff");
responseMessage.Headers.ShouldContain(x => x.Key == "X-XSS-Protection" & x.Value.First().ToString() == "1; mode=block");
responseMessage.Headers.ShouldContain(x => x.Key == "X-Frame-Options" & x.Value.First().ToString() == "SAMEORIGIN");
}
}
}

54
framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs

@ -189,6 +189,60 @@ namespace Volo.Abp.Domain.Repositories
services.ShouldContainTransient(typeof(IRepository<MyTestEntityWithInt32Pk, int>), typeof(MyTestCustomBaseRepository<MyTestEntityWithInt32Pk, int>));
}
[Fact]
public void Should_Register_Default_Repository()
{
//Arrange
var services = new ServiceCollection();
var options = new TestDbContextRegistrationOptions(typeof(MyFakeDbContext), services);
options.AddDefaultRepository<MyTestAggregateRootWithGuidPk>();
//Act
new MyTestRepositoryRegistrar(options).AddRepositories();
//MyTestAggregateRootWithoutPk
services.ShouldNotContainService(typeof(IReadOnlyRepository<MyTestAggregateRootWithoutPk>));
services.ShouldNotContainService(typeof(IBasicRepository<MyTestAggregateRootWithoutPk>));
services.ShouldNotContainService(typeof(IRepository<MyTestAggregateRootWithoutPk>));
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestDefaultRepository<MyTestAggregateRootWithGuidPk, Guid>));
}
[Fact]
public void Should_Not_Register_Default_Repository_If_Registered_Custom_Repository()
{
//Arrange
var services = new ServiceCollection();
var options = new TestDbContextRegistrationOptions(typeof(MyFakeDbContext), services);
options
.AddDefaultRepository<MyTestAggregateRootWithGuidPk>()
.AddRepository<MyTestAggregateRootWithGuidPk, MyTestAggregateRootWithDefaultPkCustomRepository>();;
//Act
new MyTestRepositoryRegistrar(options).AddRepositories();
//MyTestAggregateRootWithGuidPk
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IReadOnlyRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IReadOnlyBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IBasicRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
services.ShouldContainTransient(typeof(IRepository<MyTestAggregateRootWithGuidPk, Guid>), typeof(MyTestAggregateRootWithDefaultPkCustomRepository));
}
public class MyTestRepositoryRegistrar : RepositoryRegistrarBase<AbpCommonDbContextRegistrationOptions>
{
public MyTestRepositoryRegistrar(AbpCommonDbContextRegistrationOptions options)

2
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/IAuditLoggingDbContext.cs

@ -7,6 +7,6 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
[ConnectionStringName(AbpAuditLoggingDbProperties.ConnectionStringName)]
public interface IAuditLoggingDbContext : IEfCoreDbContext
{
DbSet<AuditLog> AuditLogs { get; set; }
DbSet<AuditLog> AuditLogs { get; }
}
}

10
modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/IBloggingDbContext.cs

@ -16,14 +16,14 @@ namespace Volo.Blogging.EntityFrameworkCore
{
DbSet<BlogUser> Users { get; }
DbSet<Blog> Blogs { get; set; }
DbSet<Blog> Blogs { get; }
DbSet<Post> Posts { get; set; }
DbSet<Post> Posts { get; }
DbSet<Comment> Comments { get; set; }
DbSet<Comment> Comments { get; }
DbSet<PostTag> PostTags { get; set; }
DbSet<PostTag> PostTags { get; }
DbSet<Tag> Tags { get; set; }
DbSet<Tag> Tags { get; }
}
}

2018
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210225092130_Page_Remove_Description.Designer.cs

File diff suppressed because it is too large

24
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210225092130_Page_Remove_Description.cs

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.CmsKit.Migrations
{
public partial class Page_Remove_Description : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Description",
table: "CmsPages");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Description",
table: "CmsPages",
type: "nvarchar(512)",
maxLength: 512,
nullable: true);
}
}
}

4
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs

@ -1545,10 +1545,6 @@ namespace Volo.CmsKit.Migrations
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");

3
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs

@ -16,8 +16,5 @@ namespace Volo.CmsKit.Admin.Pages
[Required]
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))]
public string Slug { get; set; }
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxDescriptionLength))]
public string Description { get; set; }
}
}

2
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs

@ -9,7 +9,5 @@ namespace Volo.CmsKit.Admin.Pages
public string Title { get; set; }
public string Slug { get; set; }
public string Description { get; set; }
}
}

3
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs

@ -16,8 +16,5 @@ namespace Volo.CmsKit.Admin.Pages
[Required]
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))]
public string Slug { get; set; }
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxDescriptionLength))]
public string Description { get; set; }
}
}

5
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs

@ -50,7 +50,7 @@ namespace Volo.CmsKit.Admin.Pages
{
await CheckPageSlugAsync(input.Slug);
var page = new Page(GuidGenerator.Create(), input.Title, input.Slug, input.Description, CurrentTenant?.Id);
var page = new Page(GuidGenerator.Create(), input.Title, input.Slug, CurrentTenant.Id);
await PageRepository.InsertAsync(page);
@ -69,7 +69,6 @@ namespace Volo.CmsKit.Admin.Pages
page.SetTitle(input.Title);
page.SetSlug(input.Slug);
page.Description = input.Description;
await PageRepository.UpdateAsync(page);
@ -90,4 +89,4 @@ namespace Volo.CmsKit.Admin.Pages
}
}
}
}
}

2
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs

@ -5,7 +5,5 @@
public static int MaxTitleLength { get; set; } = 256;
public static int MaxSlugLength { get; set; } = 256;
public static int MaxDescriptionLength { get; set; } = 512;
}
}

6
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Pages/Page.cs

@ -14,18 +14,14 @@ namespace Volo.CmsKit.Pages
[NotNull] public virtual string Slug { get; protected set; }
[CanBeNull] public virtual string Description { get; set; }
protected Page()
{
}
public Page(Guid id, [NotNull] string title, [NotNull] string slug, [CanBeNull] string description = null,
Guid? tenantId = null) : base(id)
public Page(Guid id, [NotNull] string title, [NotNull] string slug, [CanBeNull]Guid? tenantId = null) : base(id)
{
Title = Check.NotNullOrEmpty(title, nameof(title), PageConsts.MaxTitleLength);
Slug = Check.NotNullOrEmpty(slug, nameof(slug), PageConsts.MaxSlugLength);
Description = Check.Length(description, nameof(description), PageConsts.MaxDescriptionLength);
TenantId = tenantId;
}

1
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs

@ -179,7 +179,6 @@ namespace Volo.CmsKit.EntityFrameworkCore
b.Property(x => x.Title).IsRequired().HasMaxLength(PageConsts.MaxTitleLength);
b.Property(x => x.Slug).IsRequired().HasMaxLength(PageConsts.MaxSlugLength);
b.Property(x => x.Description).HasMaxLength(PageConsts.MaxDescriptionLength);
b.HasIndex(x => new { x.TenantId, Url = x.Slug });
});

22
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs

@ -16,16 +16,16 @@ namespace Volo.CmsKit.EntityFrameworkCore
[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)]
public interface ICmsKitDbContext : IEfCoreDbContext
{
DbSet<Content> Contents { get; set; }
DbSet<Comment> Comments { get; set; }
DbSet<CmsUser> User { get; set; }
DbSet<UserReaction> Reactions { get; set; }
DbSet<Rating> Ratings { get; set; }
DbSet<Tag> Tags { get; set; }
DbSet<EntityTag> EntityTags { get; set; }
DbSet<Page> Pages { get; set; }
DbSet<Blog> Blogs { get; set; }
DbSet<BlogPost> BlogPosts { get; set; }
DbSet<MediaDescriptor> MediaDescriptors { get; set; }
DbSet<Content> Contents { get; }
DbSet<Comment> Comments { get; }
DbSet<CmsUser> User { get; }
DbSet<UserReaction> Reactions { get; }
DbSet<Rating> Ratings { get; }
DbSet<Tag> Tags { get; }
DbSet<EntityTag> EntityTags { get; }
DbSet<Page> Pages { get; }
DbSet<Blog> Blogs { get; }
DbSet<BlogPost> BlogPosts { get; }
DbSet<MediaDescriptor> MediaDescriptors { get; }
}
}

9
modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs

@ -14,15 +14,14 @@ namespace Volo.CmsKit.Public.Pages
public virtual async Task<PageDto> FindBySlugAsync(string slug)
{
PageDto pageDto = null;
var page = await PageRepository.FindBySlugAsync(slug);
if (page !=null)
if (page == null)
{
pageDto = ObjectMapper.Map<Page, PageDto>(page);
return null;
}
return pageDto;
return ObjectMapper.Map<Page, PageDto>(page);
}
}
}

7
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PageAdminAppService_Tests.cs

@ -55,7 +55,7 @@ namespace Volo.CmsKit.Pages
{
var page = await _pageAdminAppService.GetAsync(_data.Page_1_Id);
page.Description.ShouldBe(_data.Page_1_Description);
page.Title.ShouldBe(_data.Page_1_Title);
}
[Fact]
@ -94,7 +94,6 @@ namespace Volo.CmsKit.Pages
var dto = new UpdatePageInputDto
{
Title = _data.Page_1_Title + "++",
Description = "new description",
Slug = _data.Page_1_Slug+ "test"
};
@ -107,9 +106,6 @@ namespace Volo.CmsKit.Pages
updatedPage.Slug.ShouldNotBe(_data.Page_1_Slug);
updatedPage.Slug.ShouldBe(dto.Slug);
updatedPage.Description.ShouldNotBe(_data.Page_1_Description);
updatedPage.Description.ShouldBe(dto.Description);
}
[Fact]
@ -118,7 +114,6 @@ namespace Volo.CmsKit.Pages
var dto = new UpdatePageInputDto
{
Title = _data.Page_1_Title + "++",
Description = "new description",
Slug = _data.Page_2_Slug
};

4
modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs

@ -338,13 +338,13 @@ namespace Volo.CmsKit
private async Task SeedPagesAsync()
{
var page1 = new Page(_cmsKitTestData.Page_1_Id, _cmsKitTestData.Page_1_Title, _cmsKitTestData.Page_1_Slug, _cmsKitTestData.Page_1_Description);
var page1 = new Page(_cmsKitTestData.Page_1_Id, _cmsKitTestData.Page_1_Title, _cmsKitTestData.Page_1_Slug);
var page1Content = new Content(_guidGenerator.Create(), nameof(Page), page1.Id.ToString(), _cmsKitTestData.Page_1_Content);
await _pageRepository.InsertAsync(page1);
await _contentRepository.InsertAsync(page1Content);
var page2 = new Page(_cmsKitTestData.Page_2_Id, _cmsKitTestData.Page_2_Title, _cmsKitTestData.Page_2_Slug, _cmsKitTestData.Page_2_Description);
var page2 = new Page(_cmsKitTestData.Page_2_Id, _cmsKitTestData.Page_2_Title, _cmsKitTestData.Page_2_Slug);
var page2Content = new Content(_guidGenerator.Create(), nameof(Page), page2.Id.ToString(), _cmsKitTestData.Page_2_Content);
await _pageRepository.InsertAsync(page2);

4
modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs

@ -47,8 +47,6 @@ namespace Volo.CmsKit
public string Page_1_Slug { get; } = "imagine-dragons-believer-lyrics";
public string Page_1_Description { get; } = "You can get the lyrics of the music.";
public Guid Page_1_Id { get; } = Guid.NewGuid();
public string Page_1_Content => Content_1;
@ -57,8 +55,6 @@ namespace Volo.CmsKit
public string Page_2_Slug { get; } = "imagine-dragons-believer-lyrics-2";
public string Page_2_Description { get; } = "You can get the lyrics of the music.";
public Guid Page_2_Id { get; } = Guid.NewGuid();
public string Page_2_Content => Content_2;

4
modules/cms-kit/test/Volo.CmsKit.TestBase/Pages/PageRepository_Test.cs

@ -56,7 +56,7 @@ namespace Volo.CmsKit.Pages
var page = await _pageRepository.GetBySlugAsync(_cmsKitTestData.Page_1_Slug);
page.ShouldNotBeNull();
page.Description.ShouldBe(_cmsKitTestData.Page_1_Description);
page.Title.ShouldBe(_cmsKitTestData.Page_1_Title);
}
[Fact]
@ -65,7 +65,7 @@ namespace Volo.CmsKit.Pages
var page = await _pageRepository.FindBySlugAsync(_cmsKitTestData.Page_1_Slug);
page.ShouldNotBeNull();
page.Description.ShouldBe(_cmsKitTestData.Page_1_Description);
page.Title.ShouldBe(_cmsKitTestData.Page_1_Title);
}
[Fact]

4
modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs

@ -152,12 +152,10 @@ namespace VoloDocs.Web
app.UseVirtualFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
app.UseSwagger();
app.UseSwaggerUI(options =>
{

6
modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs

@ -11,10 +11,10 @@ namespace Volo.Docs.EntityFrameworkCore
[ConnectionStringName(DocsDbProperties.ConnectionStringName)]
public interface IDocsDbContext : IEfCoreDbContext
{
DbSet<Project> Projects { get; set; }
DbSet<Project> Projects { get; }
DbSet<Document> Documents { get; set; }
DbSet<Document> Documents { get; }
DbSet<DocumentContributor> DocumentContributors { get; set; }
DbSet<DocumentContributor> DocumentContributors { get; }
}
}

2
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/IFeatureManagementDbContext.cs

@ -9,6 +9,6 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public interface IFeatureManagementDbContext : IEfCoreDbContext
{
DbSet<FeatureValue> FeatureValues { get; set; }
DbSet<FeatureValue> FeatureValues { get; }
}
}

12
modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs

@ -7,16 +7,16 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
[ConnectionStringName(AbpIdentityDbProperties.ConnectionStringName)]
public interface IIdentityDbContext : IEfCoreDbContext
{
DbSet<IdentityUser> Users { get; set; }
DbSet<IdentityUser> Users { get; }
DbSet<IdentityRole> Roles { get; set; }
DbSet<IdentityRole> Roles { get; }
DbSet<IdentityClaimType> ClaimTypes { get; set; }
DbSet<IdentityClaimType> ClaimTypes { get; }
DbSet<OrganizationUnit> OrganizationUnits { get; set; }
DbSet<OrganizationUnit> OrganizationUnits { get; }
DbSet<IdentitySecurityLog> SecurityLogs { get; set; }
DbSet<IdentitySecurityLog> SecurityLogs { get; }
DbSet<IdentityLinkUser> LinkUsers { get; set; }
DbSet<IdentityLinkUser> LinkUsers { get; }
}
}

14
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs

@ -5,6 +5,9 @@ using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Configuration;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IdentityServer.Clients;
@ -16,19 +19,26 @@ namespace Volo.Abp.IdentityServer
public ILogger<AbpCorsPolicyService> Logger { get; set; }
protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; }
protected IDistributedCache<AllowedCorsOriginsCacheItem> Cache { get; }
protected IdentityServerOptions Options { get; }
public AbpCorsPolicyService(
IDistributedCache<AllowedCorsOriginsCacheItem> cache,
IHybridServiceScopeFactory hybridServiceScopeFactory)
IHybridServiceScopeFactory hybridServiceScopeFactory,
IOptions<IdentityServerOptions> options)
{
Cache = cache;
HybridServiceScopeFactory = hybridServiceScopeFactory;
Options = options.Value;
Logger = NullLogger<AbpCorsPolicyService>.Instance;
}
public virtual async Task<bool> IsOriginAllowedAsync(string origin)
{
var cacheItem = await Cache.GetOrAddAsync(AllowedCorsOriginsCacheItem.AllOrigins, CreateCacheItemAsync);
var cacheItem = await Cache.GetOrAddAsync(AllowedCorsOriginsCacheItem.AllOrigins, CreateCacheItemAsync,
() => new DistributedCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = Options.Caching.CorsExpiration
});
var isAllowed = cacheItem.AllowedOrigins.Contains(origin, StringComparer.OrdinalIgnoreCase);

14
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerServiceCollectionExtensions.cs

@ -0,0 +1,14 @@
using IdentityServer4.Validation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Volo.Abp.IdentityServer
{
public static class AbpIdentityServerServiceCollectionExtensions
{
public static void AddAbpStrictRedirectUriValidator(this IServiceCollection services)
{
services.Replace(ServiceDescriptor.Transient<IRedirectUriValidator, AbpStrictRedirectUriValidator>());
}
}
}

44
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpStrictRedirectUriValidator.cs

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Validation;
using Microsoft.Extensions.Options;
using Volo.Abp.Text.Formatting;
namespace Volo.Abp.IdentityServer
{
public class AbpStrictRedirectUriValidator : StrictRedirectUriValidator
{
public override async Task<bool> IsRedirectUriValidAsync(string requestedUri, Client client)
{
var isAllowed = await base.IsRedirectUriValidAsync(requestedUri, client);
return isAllowed || await IsRedirectUriValidWithDomainFormatsAsync(client.RedirectUris, requestedUri);
}
public override async Task<bool> IsPostLogoutRedirectUriValidAsync(string requestedUri, Client client)
{
var isAllowed = await base.IsPostLogoutRedirectUriValidAsync(requestedUri, client);
return isAllowed || await IsRedirectUriValidWithDomainFormatsAsync(client.PostLogoutRedirectUris, requestedUri);
}
protected virtual Task<bool> IsRedirectUriValidWithDomainFormatsAsync(IEnumerable<string> uris, string requestedUri)
{
if (uris == null)
{
return Task.FromResult(false);
}
foreach (var url in uris)
{
var extractResult = FormattedStringValueExtracter.Extract(requestedUri, url, ignoreCase: true);
if (extractResult.IsMatch)
{
return Task.FromResult(true);
}
}
return Task.FromResult(false);
}
}
}

32
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Clients/ClientStore.cs

@ -1,5 +1,9 @@
using System.Threading.Tasks;
using IdentityServer4.Configuration;
using IdentityServer4.Stores;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.IdentityServer.Clients
@ -8,17 +12,39 @@ namespace Volo.Abp.IdentityServer.Clients
{
protected IClientRepository ClientRepository { get; }
protected IObjectMapper<AbpIdentityServerDomainModule> ObjectMapper { get; }
protected IDistributedCache<IdentityServer4.Models.Client> Cache { get; }
protected IdentityServerOptions Options { get; }
public ClientStore(IClientRepository clientRepository, IObjectMapper<AbpIdentityServerDomainModule> objectMapper)
public ClientStore(
IClientRepository clientRepository,
IObjectMapper<AbpIdentityServerDomainModule> objectMapper,
IDistributedCache<IdentityServer4.Models.Client> cache,
IOptions<IdentityServerOptions> options)
{
ClientRepository = clientRepository;
ObjectMapper = objectMapper;
Cache = cache;
Options = options.Value;
}
public virtual async Task<IdentityServer4.Models.Client> FindClientByIdAsync(string clientId)
{
var client = await ClientRepository.FindByClientIdAsync(clientId);
return ObjectMapper.Map<Client, IdentityServer4.Models.Client>(client);
return await GetCacheItemAsync(clientId);
}
protected virtual async Task<IdentityServer4.Models.Client> GetCacheItemAsync(string clientId)
{
return await Cache.GetOrAddAsync(clientId, async () =>
{
var client = await ClientRepository.FindByClientIdAsync(clientId);
return ObjectMapper.Map<Client, IdentityServer4.Models.Client>(client);
},
optionsFactory: () => new DistributedCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = Options.Caching.ClientStoreExpiration
},
considerUow: true);
}
}
}

74
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerCacheItemInvalidator.cs

@ -0,0 +1,74 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.IdentityResources;
namespace Volo.Abp.IdentityServer
{
public class IdentityServerCacheItemInvalidator :
ILocalEventHandler<EntityChangedEventData<Client>>,
ILocalEventHandler<EntityChangedEventData<ClientCorsOrigin>>,
ILocalEventHandler<EntityChangedEventData<IdentityResource>>,
ILocalEventHandler<EntityChangedEventData<ApiResource>>,
ILocalEventHandler<EntityChangedEventData<ApiScope>>,
ITransientDependency
{
protected IServiceProvider ServiceProvider { get; }
public IdentityServerCacheItemInvalidator(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public virtual async Task HandleEventAsync(EntityChangedEventData<Client> eventData)
{
var clientCache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.Client>>();
await clientCache.RemoveAsync(eventData.Entity.ClientId);
var corsCache = ServiceProvider.GetRequiredService<IDistributedCache<AllowedCorsOriginsCacheItem>>();
await corsCache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins);
}
public async Task HandleEventAsync(EntityChangedEventData<ClientCorsOrigin> eventData)
{
var corsCache = ServiceProvider.GetRequiredService<IDistributedCache<AllowedCorsOriginsCacheItem>>();
await corsCache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins);
}
public virtual async Task HandleEventAsync(EntityChangedEventData<IdentityResource> eventData)
{
var cache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.IdentityResource>>();
await cache.RemoveAsync(eventData.Entity.Name);
var resourcesCache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.Resources>>();
await resourcesCache.RemoveAsync(ResourceStore.AllResourcesKey);
}
public virtual async Task HandleEventAsync(EntityChangedEventData<ApiResource> eventData)
{
var cache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.ApiResource>>();
await cache.RemoveAsync(ResourceStore.ApiResourceNameCacheKeyPrefix + eventData.Entity.Name);
await cache.RemoveManyAsync(eventData.Entity.Scopes.Select(x => ResourceStore.ApiResourceScopeNameCacheKeyPrefix + x.Scope));
var resourcesCache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.Resources>>();
await resourcesCache.RemoveAsync(ResourceStore.AllResourcesKey);
}
public virtual async Task HandleEventAsync(EntityChangedEventData<ApiScope> eventData)
{
var cache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.ApiScope>>();
await cache.RemoveAsync(eventData.Entity.Name);
var resourcesCache = ServiceProvider.GetRequiredService<IDistributedCache<IdentityServer4.Models.Resources>>();
await resourcesCache.RemoveAsync(ResourceStore.AllResourcesKey);
}
}
}

141
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ResourceStore.cs

@ -1,32 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Configuration;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.IdentityResources;
using Volo.Abp.ObjectMapping;
using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource;
using ApiScope = Volo.Abp.IdentityServer.ApiScopes.ApiScope;
using IdentityResource = Volo.Abp.IdentityServer.IdentityResources.IdentityResource;
namespace Volo.Abp.IdentityServer
{
public class ResourceStore : IResourceStore
{
public const string AllResourcesKey = "AllResources";
public const string ApiResourceNameCacheKeyPrefix = "ApiResourceName_";
public const string ApiResourceScopeNameCacheKeyPrefix = "ApiResourceScopeName_";
protected IIdentityResourceRepository IdentityResourceRepository { get; }
protected IApiResourceRepository ApiResourceRepository { get; }
protected IApiScopeRepository ApiScopeRepository { get; }
protected IObjectMapper<AbpIdentityServerDomainModule> ObjectMapper { get; }
protected IDistributedCache<IdentityServer4.Models.IdentityResource> IdentityResourceCache { get; }
protected IDistributedCache<IdentityServer4.Models.ApiScope> ApiScopeCache { get; }
protected IDistributedCache<IdentityServer4.Models.ApiResource> ApiResourceCache { get; }
protected IDistributedCache<IdentityServer4.Models.Resources> ResourcesCache { get; }
protected IdentityServerOptions Options { get; }
public ResourceStore(
IIdentityResourceRepository identityResourceRepository,
IObjectMapper<AbpIdentityServerDomainModule> objectMapper,
IApiResourceRepository apiResourceRepository,
IApiScopeRepository apiScopeRepository)
IApiScopeRepository apiScopeRepository,
IDistributedCache<IdentityServer4.Models.IdentityResource> identityResourceCache,
IDistributedCache<IdentityServer4.Models.ApiScope> apiScopeCache,
IDistributedCache<IdentityServer4.Models.ApiResource> apiResourceCache,
IDistributedCache<Resources> resourcesCache,
IOptions<IdentityServerOptions> options)
{
IdentityResourceRepository = identityResourceRepository;
ObjectMapper = objectMapper;
ApiResourceRepository = apiResourceRepository;
ApiScopeRepository = apiScopeRepository;
IdentityResourceCache = identityResourceCache;
ApiScopeCache = apiScopeCache;
ApiResourceCache = apiResourceCache;
ResourcesCache = resourcesCache;
Options = options.Value;
}
/// <summary>
@ -34,8 +61,14 @@ namespace Volo.Abp.IdentityServer
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.IdentityResource>> FindIdentityResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
{
var resource = await IdentityResourceRepository.GetListByScopeNameAsync(scopeNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.IdentityResources.IdentityResource>, List<IdentityServer4.Models.IdentityResource>>(resource);
return await GetCacheItemsAsync(
IdentityResourceCache,
scopeNames,
async keys => await IdentityResourceRepository.GetListByScopeNameAsync(keys, includeDetails: true),
(models, cacheKeyPrefix)=> new List<IEnumerable<KeyValuePair<string, IdentityServer4.Models.IdentityResource>>>
{
models.Select(x => new KeyValuePair<string, IdentityServer4.Models.IdentityResource>(AddCachePrefix(x.Name, cacheKeyPrefix), x))
});
}
/// <summary>
@ -43,8 +76,14 @@ namespace Volo.Abp.IdentityServer
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.ApiScope>> FindApiScopesByNameAsync(IEnumerable<string> scopeNames)
{
var scopes = await ApiScopeRepository.GetListByNameAsync(scopeNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiScopes.ApiScope>, List<IdentityServer4.Models.ApiScope>>(scopes);
return await GetCacheItemsAsync(
ApiScopeCache,
scopeNames,
async keys => await ApiScopeRepository.GetListByNameAsync(keys, includeDetails: true),
(models, cacheKeyPrefix) => new List<IEnumerable<KeyValuePair<string, IdentityServer4.Models.ApiScope>>>
{
models.Select(x => new KeyValuePair<string, IdentityServer4.Models.ApiScope>(AddCachePrefix(x.Name, cacheKeyPrefix), x))
});
}
/// <summary>
@ -52,8 +91,16 @@ namespace Volo.Abp.IdentityServer
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.ApiResource>> FindApiResourcesByScopeNameAsync(IEnumerable<string> scopeNames)
{
var resources = await ApiResourceRepository.GetListByScopesAsync(scopeNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(resources);
return await GetCacheItemsAsync<ApiResource, IdentityServer4.Models.ApiResource>(
ApiResourceCache,
scopeNames,
async keys => await ApiResourceRepository.GetListByScopesAsync(keys, includeDetails: true),
(models, cacheKeyPrefix) =>
{
return models
.Select(model => model.Scopes.Select(scope => new KeyValuePair<string, IdentityServer4.Models.ApiResource>(AddCachePrefix(scope, cacheKeyPrefix), model)).ToList())
.Where(scopes => scopes.Any()).Cast<IEnumerable<KeyValuePair<string, IdentityServer4.Models.ApiResource>>>().ToList();
}, ApiResourceScopeNameCacheKeyPrefix);
}
/// <summary>
@ -61,8 +108,14 @@ namespace Volo.Abp.IdentityServer
/// </summary>
public virtual async Task<IEnumerable<IdentityServer4.Models.ApiResource>> FindApiResourcesByNameAsync(IEnumerable<string> apiResourceNames)
{
var resources = await ApiResourceRepository.FindByNameAsync(apiResourceNames.ToArray(), includeDetails: true);
return ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(resources);
return await GetCacheItemsAsync(
ApiResourceCache,
apiResourceNames,
async keys => await ApiResourceRepository.FindByNameAsync(keys, includeDetails: true),
(models, cacheKeyPrefix) => new List<IEnumerable<KeyValuePair<string, IdentityServer4.Models.ApiResource>>>
{
models.Select(x => new KeyValuePair<string, IdentityServer4.Models.ApiResource>(AddCachePrefix(x.Name, cacheKeyPrefix), x))
}, ApiResourceNameCacheKeyPrefix);
}
/// <summary>
@ -70,14 +123,68 @@ namespace Volo.Abp.IdentityServer
/// </summary>
public virtual async Task<IdentityServer4.Models.Resources> GetAllResourcesAsync()
{
var identityResources = await IdentityResourceRepository.GetListAsync(includeDetails: true);
var apiResources = await ApiResourceRepository.GetListAsync(includeDetails: true);
var apiScopes = await ApiScopeRepository.GetListAsync(includeDetails: true);
return new Resources(
ObjectMapper.Map<List<Volo.Abp.IdentityServer.IdentityResources.IdentityResource>, List<IdentityServer4.Models.IdentityResource>>(identityResources),
ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(apiResources),
ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiScopes.ApiScope>, List<IdentityServer4.Models.ApiScope>>(apiScopes));
return await ResourcesCache.GetOrAddAsync(AllResourcesKey, async () =>
{
var identityResources = await IdentityResourceRepository.GetListAsync(includeDetails: true);
var apiResources = await ApiResourceRepository.GetListAsync(includeDetails: true);
var apiScopes = await ApiScopeRepository.GetListAsync(includeDetails: true);
return new Resources(
ObjectMapper.Map<List<Volo.Abp.IdentityServer.IdentityResources.IdentityResource>, List<IdentityServer4.Models.IdentityResource>>(identityResources),
ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiResources.ApiResource>, List<IdentityServer4.Models.ApiResource>>(apiResources),
ObjectMapper.Map<List<Volo.Abp.IdentityServer.ApiScopes.ApiScope>, List<IdentityServer4.Models.ApiScope>>(apiScopes));
}, () => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = Options.Caching.ClientStoreExpiration
});
}
protected virtual async Task<IEnumerable<TModel>> GetCacheItemsAsync<TEntity, TModel>(
IDistributedCache<TModel> cache,
IEnumerable<string> keys,
Func<string[], Task<List<TEntity>>> entityFactory,
Func<List<TModel>, string, List<IEnumerable<KeyValuePair<string, TModel>>>> cacheItemsFactory,
string cacheKeyPrefix = null)
where TModel : class
{
var cacheItems = await cache.GetManyAsync(AddCachePrefix(keys, cacheKeyPrefix));
if (cacheItems.All(x => x.Value != null))
{
return cacheItems.Select(x => x.Value);
}
var otherKeys = RemoveCachePrefix(cacheItems.Where(x => x.Value == null).Select(x => x.Key), cacheKeyPrefix).ToArray();
var otherModels = ObjectMapper.Map<List<TEntity>, List<TModel>>(await entityFactory(otherKeys));
var otherCacheItems = cacheItemsFactory(otherModels, cacheKeyPrefix).ToList();
foreach (var item in otherCacheItems)
{
await cache.SetManyAsync(item, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = Options.Caching.ClientStoreExpiration
});
}
return cacheItems.Where(x => x.Value != null).Select(x => x.Value).Concat(otherModels);
}
protected virtual IEnumerable<string> AddCachePrefix(IEnumerable<string> keys, string prefix)
{
return prefix == null ? keys : keys.Select(x => AddCachePrefix(x, prefix));
}
protected virtual string AddCachePrefix(string key, string prefix)
{
return prefix == null ? key : prefix + key;
}
protected virtual IEnumerable<string> RemoveCachePrefix(IEnumerable<string> keys, string prefix)
{
return prefix == null ? keys : keys.Select(x => RemoveCachePrefix(x, prefix));
}
protected virtual string RemoveCachePrefix(string key, string prefix)
{
return prefix == null ? key : key.RemovePreFix(prefix);
}
}
}

46
modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IIdentityServerDbContext.cs

@ -17,64 +17,64 @@ namespace Volo.Abp.IdentityServer.EntityFrameworkCore
{
#region ApiResource
DbSet<ApiResource> ApiResources { get; set; }
DbSet<ApiResource> ApiResources { get; }
DbSet<ApiResourceSecret> ApiResourceSecrets { get; set; }
DbSet<ApiResourceSecret> ApiResourceSecrets { get; }
DbSet<ApiResourceClaim> ApiResourceClaims { get; set; }
DbSet<ApiResourceClaim> ApiResourceClaims { get; }
DbSet<ApiResourceScope> ApiResourceScopes { get; set; }
DbSet<ApiResourceScope> ApiResourceScopes { get; }
DbSet<ApiResourceProperty> ApiResourceProperties { get; set; }
DbSet<ApiResourceProperty> ApiResourceProperties { get; }
#endregion
#region ApiScope
DbSet<ApiScope> ApiScopes { get; set; }
DbSet<ApiScope> ApiScopes { get; }
DbSet<ApiScopeClaim> ApiScopeClaims { get; set; }
DbSet<ApiScopeClaim> ApiScopeClaims { get; }
DbSet<ApiScopeProperty> ApiScopeProperties { get; set; }
DbSet<ApiScopeProperty> ApiScopeProperties { get; }
#endregion
#region IdentityResource
DbSet<IdentityResource> IdentityResources { get; set; }
DbSet<IdentityResource> IdentityResources { get; }
DbSet<IdentityResourceClaim> IdentityClaims { get; set; }
DbSet<IdentityResourceClaim> IdentityClaims { get; }
DbSet<IdentityResourceProperty> IdentityResourceProperties { get; set; }
DbSet<IdentityResourceProperty> IdentityResourceProperties { get; }
#endregion
#region Client
DbSet<Client> Clients { get; set; }
DbSet<Client> Clients { get; }
DbSet<ClientGrantType> ClientGrantTypes { get; set; }
DbSet<ClientGrantType> ClientGrantTypes { get; }
DbSet<ClientRedirectUri> ClientRedirectUris { get; set; }
DbSet<ClientRedirectUri> ClientRedirectUris { get; }
DbSet<ClientPostLogoutRedirectUri> ClientPostLogoutRedirectUris { get; set; }
DbSet<ClientPostLogoutRedirectUri> ClientPostLogoutRedirectUris { get; }
DbSet<ClientScope> ClientScopes { get; set; }
DbSet<ClientScope> ClientScopes { get; }
DbSet<ClientSecret> ClientSecrets { get; set; }
DbSet<ClientSecret> ClientSecrets { get; }
DbSet<ClientClaim> ClientClaims { get; set; }
DbSet<ClientClaim> ClientClaims { get; }
DbSet<ClientIdPRestriction> ClientIdPRestrictions { get; set; }
DbSet<ClientIdPRestriction> ClientIdPRestrictions { get; }
DbSet<ClientCorsOrigin> ClientCorsOrigins { get; set; }
DbSet<ClientCorsOrigin> ClientCorsOrigins { get; }
DbSet<ClientProperty> ClientProperties { get; set; }
DbSet<ClientProperty> ClientProperties { get; }
#endregion
DbSet<PersistedGrant> PersistedGrants { get; set; }
DbSet<PersistedGrant> PersistedGrants { get; }
DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
DbSet<DeviceFlowCodes> DeviceFlowCodes { get; }
}
}

69
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpStrictRedirectUriValidator_Tests.cs

@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Validation;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace Volo.Abp.IdentityServer
{
public class AbpStrictRedirectUriValidator_Tests : AbpIdentityServerTestBase
{
private readonly IRedirectUriValidator _abpStrictRedirectUriValidator;
private readonly Client _testClient = new Client
{
RedirectUris = new List<string>
{
"https://{0}.api.abp.io:8080/signin-oidc",
"http://{0}.ng.abp.io/index.html"
},
PostLogoutRedirectUris = new List<string>
{
"https://{0}.api.abp.io:8080/signin-oidc",
"http://{0}.ng.abp.io/index.html"
}
};
public AbpStrictRedirectUriValidator_Tests()
{
_abpStrictRedirectUriValidator = GetRequiredService<IRedirectUriValidator>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.AddAbpStrictRedirectUriValidator();
}
[Fact]
public void Should_Register_AbpStrictRedirectUriValidator()
{
_abpStrictRedirectUriValidator.GetType().ShouldBe(typeof(AbpStrictRedirectUriValidator));
}
[Fact]
public async Task IsRedirectUriValidAsync()
{
(await _abpStrictRedirectUriValidator.IsRedirectUriValidAsync("https://t1.api.abp.io:8080/signin-oidc", _testClient)).ShouldBeTrue();
(await _abpStrictRedirectUriValidator.IsRedirectUriValidAsync("http://t2.ng.abp.io/index.html", _testClient)).ShouldBeTrue();
(await _abpStrictRedirectUriValidator.IsRedirectUriValidAsync("https://api.abp:8080/", _testClient)).ShouldBeFalse();
(await _abpStrictRedirectUriValidator.IsRedirectUriValidAsync("http://ng.abp.io", _testClient)).ShouldBeFalse();
(await _abpStrictRedirectUriValidator.IsRedirectUriValidAsync("https://api.t1.abp:8080/", _testClient)).ShouldBeFalse();
(await _abpStrictRedirectUriValidator.IsRedirectUriValidAsync("http://ng.t1.abp.io", _testClient)).ShouldBeFalse();
}
[Fact]
public async Task IsPostLogoutRedirectUriValidAsync()
{
(await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://t1.api.abp.io:8080/signin-oidc", _testClient)).ShouldBeTrue();
(await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://t2.ng.abp.io/index.html", _testClient)).ShouldBeTrue();
(await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://api.abp:8080/", _testClient)).ShouldBeFalse();
(await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://ng.abp.io", _testClient)).ShouldBeFalse();
(await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("https://api.t1.abp:8080/", _testClient)).ShouldBeFalse();
(await _abpStrictRedirectUriValidator.IsPostLogoutRedirectUriValidAsync("http://ng.t1.abp.io", _testClient)).ShouldBeFalse();
}
}
}

138
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/Cache/IdentityServerCacheItemInvalidator_Tests.cs

@ -0,0 +1,138 @@
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Shouldly;
using Volo.Abp.Caching;
using Volo.Abp.IdentityServer.ApiResources;
using Volo.Abp.IdentityServer.ApiScopes;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.IdentityResources;
using Xunit;
using ApiResource = IdentityServer4.Models.ApiResource;
using ApiScope = IdentityServer4.Models.ApiScope;
using Client = IdentityServer4.Models.Client;
using IdentityResource = IdentityServer4.Models.IdentityResource;
namespace Volo.Abp.IdentityServer.Cache
{
public class IdentityServerCacheItemInvalidator_Tests : AbpIdentityServerTestBase
{
private readonly IClientStore _clientStore;
private readonly IResourceStore _resourceStore;
private readonly IClientRepository _clientRepository;
private readonly IIdentityResourceRepository _identityResourceRepository;
private readonly IApiResourceRepository _apiResourceRepository;
private readonly IApiScopeRepository _apiScopeRepository;
private readonly IDistributedCache<Client> _clientCache;
private readonly IDistributedCache<IdentityResource> _identityResourceCache;
private readonly IDistributedCache<ApiResource>_apiResourceCache;
private readonly IDistributedCache<ApiScope> _apiScopeCache;
private readonly IDistributedCache<Resources> _resourceCache;
private readonly AbpIdentityServerTestData _testData;
public IdentityServerCacheItemInvalidator_Tests()
{
_clientStore = GetRequiredService<IClientStore>();
_resourceStore = GetRequiredService<IResourceStore>();
_clientRepository = GetRequiredService<IClientRepository>();
_identityResourceRepository = GetRequiredService<IIdentityResourceRepository>();
_apiResourceRepository = GetRequiredService<IApiResourceRepository>();
_apiScopeRepository = GetRequiredService<IApiScopeRepository>();
_clientCache = GetRequiredService<IDistributedCache<Client>>();
_identityResourceCache = GetRequiredService<IDistributedCache<IdentityResource>>();
_apiResourceCache = GetRequiredService<IDistributedCache<ApiResource>>();
_apiScopeCache = GetRequiredService<IDistributedCache<ApiScope>>();
_resourceCache = GetRequiredService<IDistributedCache<Resources>>();
_testData = GetRequiredService<AbpIdentityServerTestData>();
}
[Fact]
public async Task Models_Should_Cached_And_Invalidator_When_Its_Changed()
{
//client
var clientId = "ClientId1";
(await _clientCache.GetAsync(clientId)).ShouldBeNull();
var client = await _clientStore.FindClientByIdAsync(clientId);
client.ShouldNotBeNull();
var clientCacheItem = await _clientCache.GetAsync(clientId);
clientCacheItem.ShouldNotBeNull();
await _clientRepository.DeleteAsync(_testData.Client1Id);
(await _clientCache.GetAsync(clientId)).ShouldBeNull();
//Api Resource
var newApiResource1 = "NewApiResource1";
var newApiResource2 = "NewApiResource2";
var testApiResourceName1 = "Test-ApiResource-Name-1";
var testApiResourceApiScopeName1 = "Test-ApiResource-ApiScope-Name-1";
var newApiResources = new[] {newApiResource1, newApiResource2};
//FindApiResourcesByNameAsync
(await _apiResourceCache.GetAsync(newApiResource1)).ShouldBeNull();
(await _apiResourceCache.GetAsync(newApiResource2)).ShouldBeNull();
await _resourceStore.FindApiResourcesByNameAsync(newApiResources);
(await _apiResourceCache.GetAsync(ResourceStore.ApiResourceNameCacheKeyPrefix + newApiResource1)).ShouldNotBeNull();
(await _apiResourceCache.GetAsync(ResourceStore.ApiResourceNameCacheKeyPrefix + newApiResource2)).ShouldNotBeNull();
var apiResource1 = await _apiResourceRepository.FindByNameAsync(newApiResource1);
await _apiResourceRepository.DeleteAsync(apiResource1);
(await _apiResourceCache.GetAsync(newApiResource1)).ShouldBeNull();
var apiResource2 = await _apiResourceRepository.FindByNameAsync(newApiResource2);
await _apiResourceRepository.DeleteAsync(apiResource2);
(await _apiResourceCache.GetAsync(newApiResource2)).ShouldBeNull();
//FindApiResourcesByScopeNameAsync
(await _apiResourceCache.GetAsync(ResourceStore.ApiResourceScopeNameCacheKeyPrefix + testApiResourceApiScopeName1)).ShouldBeNull();
await _resourceStore.FindApiResourcesByScopeNameAsync(new []{ testApiResourceApiScopeName1 });
(await _apiResourceCache.GetAsync(ResourceStore.ApiResourceScopeNameCacheKeyPrefix + testApiResourceApiScopeName1)).ShouldNotBeNull();
var testApiResource1 = await _apiResourceRepository.FindByNameAsync(testApiResourceName1);
await _apiResourceRepository.DeleteAsync(testApiResource1);
(await _apiResourceCache.GetAsync(ResourceStore.ApiResourceScopeNameCacheKeyPrefix + testApiResourceApiScopeName1)).ShouldBeNull();
//Identity Resource
var testIdentityResourceName = "Test-Identity-Resource-Name-1";
var testIdentityResourceNames = new[] {testIdentityResourceName};
(await _identityResourceCache.GetAsync(testIdentityResourceName)).ShouldBeNull();
await _resourceStore.FindIdentityResourcesByScopeNameAsync(testIdentityResourceNames);
(await _identityResourceCache.GetAsync(testIdentityResourceName)).ShouldNotBeNull();
var testIdentityResource = await _identityResourceRepository.FindByNameAsync(testIdentityResourceName);
await _identityResourceRepository.DeleteAsync(testIdentityResource);
(await _identityResourceCache.GetAsync(testIdentityResourceName)).ShouldBeNull();
//Api Scope
var testApiScopeName = "Test-ApiScope-Name-1";
var testApiScopeNames = new[] {testApiScopeName};
(await _apiScopeCache.GetAsync(testApiScopeName)).ShouldBeNull();
await _resourceStore.FindApiScopesByNameAsync(testApiScopeNames);
(await _apiScopeCache.GetAsync(testApiScopeName)).ShouldNotBeNull();
var testApiScope = await _apiScopeRepository.GetByNameAsync(testApiScopeName);
await _apiScopeRepository.DeleteAsync(testApiScope);
(await _apiScopeCache.GetAsync(testApiScopeName)).ShouldBeNull();
//Resources
(await _resourceCache.GetAsync(ResourceStore.AllResourcesKey)).ShouldBeNull();
await _resourceStore.GetAllResourcesAsync();
(await _resourceCache.GetAsync(ResourceStore.AllResourcesKey)).ShouldNotBeNull();
await _identityResourceRepository.DeleteAsync(_testData.IdentityResource1Id);
(await _resourceCache.GetAsync(ResourceStore.AllResourcesKey)).ShouldBeNull();
}
}
}

79
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/ResourceStore_Cache_Tests.cs

@ -0,0 +1,79 @@
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Stores;
using Shouldly;
using Volo.Abp.IdentityServer.ApiResources;
using Xunit;
namespace Volo.Abp.IdentityServer
{
public class ResourceStore_Cache_Tests : AbpIdentityServerDomainTestBase
{
private readonly IResourceStore _resourceStore;
public ResourceStore_Cache_Tests()
{
_resourceStore = GetRequiredService<IResourceStore>();
}
[Fact]
public async Task FindIdentityResourcesByScopeNameAsync()
{
var identityResources = (await _resourceStore.FindIdentityResourcesByScopeNameAsync(new[] {"Test-Identity-Resource-Name-1"})).ToList();
identityResources.ShouldNotBeEmpty();
identityResources.Count.ShouldBe(1);
identityResources.First().Name.ShouldBe("Test-Identity-Resource-Name-1");
var identityResources2 = (await _resourceStore.FindIdentityResourcesByScopeNameAsync(new[] {"Test-Identity-Resource-Name-1", "NewIdentityResource1"})).ToList();
identityResources2.ShouldNotBeEmpty();
identityResources2.Count.ShouldBe(2);
identityResources2.ShouldContain(x => x.Name == "NewIdentityResource1");
identityResources2.ShouldContain(x => x.Name == identityResources.First().Name);
}
[Fact]
public async Task FindApiScopesByNameAsync()
{
var apiScopes1 = (await _resourceStore.FindApiScopesByNameAsync(new[] {"Test-ApiScope-Name-1"})).ToList();
apiScopes1.ShouldNotBeEmpty();
apiScopes1.Count.ShouldBe(1);
apiScopes1.First().Name.ShouldBe("Test-ApiScope-Name-1");
var apiScopes2 = (await _resourceStore.FindApiScopesByNameAsync(new[] {"Test-ApiScope-Name-1", "Test-ApiScope-Name-2"})).ToList();
apiScopes2.ShouldNotBeEmpty();
apiScopes2.Count.ShouldBe(2);
apiScopes2.ShouldContain(x => x.Name == "Test-ApiScope-Name-1");
apiScopes2.ShouldContain(x => x.Name == apiScopes1.First().Name);
}
[Fact]
public async Task FindApiResourcesByScopeNameAsync()
{
var apiResources1 = (await _resourceStore.FindApiResourcesByScopeNameAsync(new[] {"Test-ApiResource-ApiScope-Name-1"})).ToList();
apiResources1.ShouldNotBeEmpty();
apiResources1.Count.ShouldBe(1);
apiResources1.First().Name.ShouldBe("Test-ApiResource-Name-1");
var apiResources2 = (await _resourceStore.FindApiResourcesByScopeNameAsync(new[] {"Test-ApiResource-ApiScope-Name-1", nameof(ApiResourceScope.Scope)})).ToList();
apiResources2.ShouldNotBeEmpty();
apiResources2.Count.ShouldBe(2);
apiResources2.ShouldContain(x => x.Name == "Test-ApiResource-Name-1");
apiResources2.ShouldContain(x => x.Name == apiResources1.First().Name);
}
[Fact]
public async Task FindApiResourcesByNameAsync()
{
var apiResources1 = (await _resourceStore.FindApiResourcesByNameAsync(new[] {"Test-ApiResource-Name-1"})).ToList();
apiResources1.ShouldNotBeEmpty();
apiResources1.Count.ShouldBe(1);
apiResources1.First().Name.ShouldBe("Test-ApiResource-Name-1");
var apiResources2 = (await _resourceStore.FindApiResourcesByNameAsync(new[] {"Test-ApiResource-Name-1", "NewApiResource1"})).ToList();
apiResources2.ShouldNotBeEmpty();
apiResources2.Count.ShouldBe(2);
apiResources2.ShouldContain(x => x.Name == "NewApiResource1");
apiResources2.ShouldContain(x => x.Name == apiResources1.First().Name);
}
}
}

3
modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs

@ -75,6 +75,9 @@ namespace Volo.Abp.IdentityServer
apiScope.AddUserClaim("Test-ApiScope-Claim-Type-1");
await _apiScopeRepository.InsertAsync(apiScope);
var apiScope2 = new ApiScope(_guidGenerator.Create(), "Test-ApiScope-Name-2");
await _apiScopeRepository.InsertAsync(apiScope2);
}
private async Task AddApiResources()

2
modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs

@ -7,6 +7,6 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore
[ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)]
public interface IPermissionManagementDbContext : IEfCoreDbContext
{
DbSet<PermissionGrant> PermissionGrants { get; set; }
DbSet<PermissionGrant> PermissionGrants { get; }
}
}

2
modules/setting-management/src/Volo.Abp.SettingManagement.Application.Contracts/Volo/Abp/SettingManagement/SettingManagementPermissionDefinitionProvider.cs

@ -10,7 +10,7 @@ namespace Volo.Abp.SettingManagement
public override void Define(IPermissionDefinitionContext context)
{
var moduleGroup = context.AddGroup(SettingManagementPermissions.GroupName, L("Permission:SettingManagement"));
moduleGroup.AddPermission(SettingManagementPermissions.EmailSetting, L("Permission:EmailSetting"), multiTenancySide: MultiTenancySides.Host);
moduleGroup.AddPermission(SettingManagementPermissions.Emailing, L("Permission:Emailing"), multiTenancySide: MultiTenancySides.Host);
}
private static LocalizableString L(string name)

2
modules/setting-management/src/Volo.Abp.SettingManagement.Application.Contracts/Volo/Abp/SettingManagement/SettingManagementPermissions.cs

@ -6,7 +6,7 @@ namespace Volo.Abp.SettingManagement
{
public const string GroupName = "SettingManagement";
public const string EmailSetting = GroupName + ".EmailSetting";
public const string Emailing = GroupName + ".Emailing";
public static string[] GetAll()
{

2
modules/setting-management/src/Volo.Abp.SettingManagement.Application/Volo/Abp/SettingManagement/EmailSettingsAppService.cs

@ -5,7 +5,7 @@ using Volo.Abp.Emailing;
namespace Volo.Abp.SettingManagement
{
[Authorize(SettingManagementPermissions.EmailSetting)]
[Authorize(SettingManagementPermissions.Emailing)]
public class EmailSettingsAppService : SettingManagementAppServiceBase, IEmailSettingsAppService
{
protected ISettingManager SettingManager { get; }

2
modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/AbpSettingManagementBlazorModule.cs

@ -36,7 +36,7 @@ namespace Volo.Abp.SettingManagement.Blazor
Configure<SettingManagementComponentOptions>(options =>
{
options.Contributors.Add(new EmailSettingPageContributor());
options.Contributors.Add(new EmailingPageContributor());
});
}
}

6
modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Settings/EmailSettingPageContributor.cs → modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Settings/EmailingPageContributor.cs

@ -7,7 +7,7 @@ using Volo.Abp.SettingManagement.Localization;
namespace Volo.Abp.SettingManagement.Blazor.Settings
{
public class EmailSettingPageContributor: ISettingComponentContributor
public class EmailingPageContributor: ISettingComponentContributor
{
public async Task ConfigureAsync(SettingComponentCreationContext context)
{
@ -20,7 +20,7 @@ namespace Volo.Abp.SettingManagement.Blazor.Settings
context.Groups.Add(
new SettingComponentGroup(
"Volo.Abp.SettingManagement",
l["Menu:EmailSetting"],
l["Menu:Emailing"],
typeof(EmailSettingGroupViewComponent)
)
);
@ -35,7 +35,7 @@ namespace Volo.Abp.SettingManagement.Blazor.Settings
{
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
return await authorizationService.IsGrantedAsync(SettingManagementPermissions.EmailSetting);
return await authorizationService.IsGrantedAsync(SettingManagementPermissions.Emailing);
}
}
}

4
modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/de-DE.json

@ -4,8 +4,8 @@
"Settings": "Einstellungen",
"SuccessfullySaved": "Erfolgreich gespeichert",
"Permission:SettingManagement": "Einstellungen-Verwaltung",
"Permission:EmailSetting": "E-Mail-Einstellungen",
"Menu:EmailSetting": "E-Mail-Einstellung",
"Permission:Emailing": "E-Mail",
"Menu:Emailing": "E-Mail",
"SmtpHost": "Host",
"SmtpPort": "Port",
"SmtpUserName": "Benutzername",

4
modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json

@ -4,8 +4,8 @@
"Settings": "Settings",
"SuccessfullySaved": "Successfully saved",
"Permission:SettingManagement": "Setting Management",
"Permission:EmailSetting": "Email Setting",
"Menu:EmailSetting": "Email Setting",
"Permission:Emailing": "Emailing",
"Menu:Emailing": "Emailing",
"SmtpHost": "Host",
"SmtpPort": "Port",
"SmtpUserName": "User name",

4
modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/es.json

@ -4,8 +4,8 @@
"Settings": "Configuraciones",
"SuccessfullySaved": "Guardado correctamente",
"Permission:SettingManagement": "Configuraciones de correo electronico",
"Permission:EmailSetting": "Configuración de correo electrónico",
"Menu:EmailSetting": "Configuración de correo electrónico",
"Permission:Emailing": "Configuración",
"Menu:Emailing": "Configuración",
"SmtpHost": "Host",
"SmtpPort": "Puerto",
"SmtpUserName": "Nombre de usuario",

4
modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/tr.json

@ -4,8 +4,8 @@
"Settings": "Ayarlar",
"SuccessfullySaved": "Başarıyla Kaydedildi",
"Permission:SettingManagement": "Ayarlar yönetimi",
"Permission:EmailSetting": "Email Ayarlar",
"Menu:EmailSetting": "Email Ayarlar",
"Permission:Emailing": "Email",
"Menu:Emailing": "Email",
"SmtpHost": "Sunucu",
"SmtpPort": "Port",
"SmtpUserName": "Kullanıcı adı",

4
modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hans.json

@ -4,8 +4,8 @@
"Settings": "设置",
"SuccessfullySaved": "保存成功",
"Permission:SettingManagement": "设置管理",
"Permission:EmailSetting": "邮件设置",
"Menu:EmailSetting": "邮件设置",
"Permission:Emailing": "邮件",
"Menu:Emailing": "邮件",
"SmtpHost": "主机",
"SmtpPort": "端口",
"SmtpUserName": "用户名",

2
modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/ISettingManagementDbContext.cs

@ -9,6 +9,6 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore
[ConnectionStringName(AbpSettingManagementDbProperties.ConnectionStringName)]
public interface ISettingManagementDbContext : IEfCoreDbContext
{
DbSet<Setting> Settings { get; set; }
DbSet<Setting> Settings { get; }
}
}

2
modules/setting-management/src/Volo.Abp.SettingManagement.Web/AbpSettingManagementWebModule.cs

@ -34,7 +34,7 @@ namespace Volo.Abp.SettingManagement.Web
Configure<SettingManagementPageOptions>(options =>
{
options.Contributors.Add(new EmailSettingPageContributor());
options.Contributors.Add(new EmailingPageContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>

6
modules/setting-management/src/Volo.Abp.SettingManagement.Web/Settings/EmailSettingPageContributor.cs → modules/setting-management/src/Volo.Abp.SettingManagement.Web/Settings/EmailingPageContributor.cs

@ -8,7 +8,7 @@ using Volo.Abp.SettingManagement.Web.Pages.SettingManagement.Components.EmailSet
namespace Volo.Abp.SettingManagement.Web.Settings
{
public class EmailSettingPageContributor: ISettingPageContributor
public class EmailingPageContributor: ISettingPageContributor
{
public async Task ConfigureAsync(SettingPageCreationContext context)
{
@ -21,7 +21,7 @@ namespace Volo.Abp.SettingManagement.Web.Settings
context.Groups.Add(
new SettingPageGroup(
"Volo.Abp.EmailSetting",
l["Menu:EmailSetting"],
l["Menu:Emailing"],
typeof(EmailSettingGroupViewComponent)
)
);
@ -36,7 +36,7 @@ namespace Volo.Abp.SettingManagement.Web.Settings
{
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
return await authorizationService.IsGrantedAsync(SettingManagementPermissions.EmailSetting);
return await authorizationService.IsGrantedAsync(SettingManagementPermissions.Emailing);
}
}
}

4
modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/ITenantManagementDbContext.cs

@ -9,8 +9,8 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore
[ConnectionStringName(AbpTenantManagementDbProperties.ConnectionStringName)]
public interface ITenantManagementDbContext : IEfCoreDbContext
{
DbSet<Tenant> Tenants { get; set; }
DbSet<Tenant> Tenants { get; }
DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }
DbSet<TenantConnectionString> TenantConnectionStrings { get; }
}
}

4
npm/ng-packs/apps/dev-app/src/environments/environment.ts

@ -38,5 +38,9 @@ export const environment = {
url: 'https://localhost:44305',
rootNamespace: 'Volo.Abp',
},
AbpSettingManagement: {
url: 'https://localhost:44305',
rootNamespace: 'Volo.Abp.SettingManagement',
},
},
} as Environment;

68
npm/ng-packs/packages/setting-management/config/src/components/email-setting-group/email-setting-group.component.html

@ -0,0 +1,68 @@
<h2>{{ 'AbpSettingManagement::Menu:Emailing' | abpLocalization }}</h2>
<hr class="my-3" />
<form *ngIf="form" [formGroup]="form" (ngSubmit)="submit()" validateOnSubmit>
<div class="form-group">
<label>{{ 'AbpSettingManagement::DefaultFromDisplayName' | abpLocalization }}</label>
<input type="text" class="form-control" formControlName="defaultFromDisplayName" />
</div>
<div class="form-group">
<label>{{ 'AbpSettingManagement::DefaultFromAddress' | abpLocalization }}</label>
<input type="text" class="form-control" formControlName="defaultFromAddress" />
</div>
<div class="form-group">
<label>{{ 'AbpSettingManagement::SmtpHost' | abpLocalization }}</label>
<input type="text" class="form-control" formControlName="smtpHost" />
</div>
<div class="form-group">
<label>{{ 'AbpSettingManagement::SmtpPort' | abpLocalization }}</label>
<input type="number" class="form-control" formControlName="smtpPort" />
</div>
<div class="custom-checkbox custom-control mb-2">
<input
type="checkbox"
id="smtp-enable-ssl"
class="custom-control-input"
formControlName="smtpEnableSsl"
/>
<label class="custom-control-label" for="smtp-enable-ssl">{{
'AbpSettingManagement::SmtpEnableSsl' | abpLocalization
}}</label>
</div>
<div class="custom-checkbox custom-control mb-2">
<input
type="checkbox"
id="smtp-use-default-credentials"
class="custom-control-input"
formControlName="smtpUseDefaultCredentials"
/>
<label class="custom-control-label" for="smtp-use-default-credentials">{{
'AbpSettingManagement::SmtpUseDefaultCredentials' | abpLocalization
}}</label>
</div>
<div [@collapse]="form.get('smtpUseDefaultCredentials').value ? 'collapsed' : 'expanded'">
<div class="form-group">
<label>{{ 'AbpSettingManagement::SmtpDomain' | abpLocalization }}</label>
<input type="text" class="form-control" formControlName="smtpDomain" />
</div>
<div class="form-group">
<label>{{ 'AbpSettingManagement::SmtpUserName' | abpLocalization }}</label>
<input type="text" class="form-control" formControlName="smtpUserName" />
</div>
<div class="form-group">
<label>{{ 'AbpSettingManagement::SmtpPassword' | abpLocalization }}</label>
<input type="text" class="form-control" formControlName="smtpPassword" />
</div>
</div>
<hr />
<button type="submit" class="btn btn-primary">
{{ 'AbpSettingManagement::Save' | abpLocalization }}
</button>
</form>

60
npm/ng-packs/packages/setting-management/config/src/components/email-setting-group/email-setting-group.component.ts

@ -0,0 +1,60 @@
import { collapse, ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { finalize } from 'rxjs/operators';
import { EmailSettingsService } from '../../proxy/email-settings.service';
import { EmailSettingsDto } from '../../proxy/models';
@Component({
selector: 'abp-email-setting-group',
templateUrl: 'email-setting-group.component.html',
animations: [collapse],
})
export class EmailSettingGroupComponent implements OnInit {
form: FormGroup;
saving = false;
constructor(
private emailSettingsService: EmailSettingsService,
private fb: FormBuilder,
private toasterService: ToasterService,
) {}
ngOnInit() {
this.getData();
}
private getData() {
this.emailSettingsService.get().subscribe(res => {
this.buildForm(res);
});
}
private buildForm(emailSettings: EmailSettingsDto) {
this.form = this.fb.group({
defaultFromDisplayName: [emailSettings.defaultFromDisplayName, [Validators.required]],
defaultFromAddress: [emailSettings.defaultFromAddress, [Validators.required]],
smtpHost: [emailSettings.smtpHost],
smtpPort: [emailSettings.smtpPort, [Validators.required]],
smtpEnableSsl: [emailSettings.smtpEnableSsl],
smtpUseDefaultCredentials: [emailSettings.smtpUseDefaultCredentials],
smtpDomain: [emailSettings.smtpDomain],
smtpUserName: [emailSettings.smtpUserName],
smtpPassword: [emailSettings.smtpPassword],
});
}
submit() {
if (this.saving || this.form.invalid) return;
this.saving = true;
this.emailSettingsService
.update(this.form.value)
.pipe(finalize(() => (this.saving = false)))
.subscribe(() => {
this.toasterService.success('AbpSettingManagement::SuccessfullySaved');
this.getData();
});
}
}

1
npm/ng-packs/packages/setting-management/config/src/enums/index.ts

@ -1 +1,2 @@
export * from './route-names';
export * from './setting-tab-names';

3
npm/ng-packs/packages/setting-management/config/src/enums/setting-tab-names.ts

@ -0,0 +1,3 @@
export const enum eSettingManamagementSettingTabNames {
EmailSettingGroup = 'AbpSettingManagement::Menu:Emailing',
}

1
npm/ng-packs/packages/setting-management/config/src/providers/index.ts

@ -1 +1,2 @@
export * from './route.provider';
export * from './setting-tab.provider';

26
npm/ng-packs/packages/setting-management/config/src/providers/setting-tab.provider.ts

@ -0,0 +1,26 @@
import { SettingTabsService } from '@abp/ng.core';
import { APP_INITIALIZER } from '@angular/core';
import { EmailSettingGroupComponent } from '../components/email-setting-group/email-setting-group.component';
import { eSettingManamagementSettingTabNames } from '../enums/setting-tab-names';
export const SETTING_MANAGEMENT_SETTING_TAB_PROVIDERS = [
{
provide: APP_INITIALIZER,
useFactory: configureSettingTabs,
deps: [SettingTabsService],
multi: true,
},
];
export function configureSettingTabs(settingTabs: SettingTabsService) {
return () => {
settingTabs.add([
{
name: eSettingManamagementSettingTabNames.EmailSettingGroup,
order: 1,
requiredPolicy: 'SettingManagement.Emailing',
component: EmailSettingGroupComponent,
},
]);
};
}

17
npm/ng-packs/packages/setting-management/config/src/proxy/README.md

@ -0,0 +1,17 @@
# Proxy Generation Output
This directory includes the output of the latest proxy generation.
The files and folders in it will be overwritten when proxy generation is run again.
Therefore, please do not place your own content in this folder.
In addition, `generate-proxy.json` works like a lock file.
It includes information used by the proxy generator, so please do not delete or modify it.
Finally, the name of the files and folders should not be changed for two reasons:
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content.
- ABP Suite generates files which include imports from this folder.
> **Important Notice:** If you are building a module and are planning to publish to npm,
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case,
> please make sure you export files directly and not from barrel exports. In other words,
> do not include index.ts exports in your public-api.ts exports.

27
npm/ng-packs/packages/setting-management/config/src/proxy/email-settings.service.ts

@ -0,0 +1,27 @@
import type { EmailSettingsDto, UpdateEmailSettingsDto } from './models';
import { RestService } from '@abp/ng.core';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class EmailSettingsService {
apiName = 'SettingManagement';
get = () =>
this.restService.request<any, EmailSettingsDto>({
method: 'GET',
url: '/api/setting-management/emailing',
},
{ apiName: this.apiName });
update = (input: UpdateEmailSettingsDto) =>
this.restService.request<any, void>({
method: 'POST',
url: '/api/setting-management/emailing',
body: input,
},
{ apiName: this.apiName });
constructor(private restService: RestService) {}
}

4745
npm/ng-packs/packages/setting-management/config/src/proxy/generate-proxy.json

File diff suppressed because it is too large

2
npm/ng-packs/packages/setting-management/config/src/proxy/index.ts

@ -0,0 +1,2 @@
export * from './email-settings.service';
export * from './models';

24
npm/ng-packs/packages/setting-management/config/src/proxy/models.ts

@ -0,0 +1,24 @@
export interface EmailSettingsDto {
smtpHost?: string;
smtpPort: number;
smtpUserName?: string;
smtpPassword?: string;
smtpDomain?: string;
smtpEnableSsl: boolean;
smtpUseDefaultCredentials: boolean;
defaultFromAddress?: string;
defaultFromDisplayName?: string;
}
export interface UpdateEmailSettingsDto {
smtpHost?: string;
smtpPort: number;
smtpUserName?: string;
smtpPassword?: string;
smtpDomain?: string;
smtpEnableSsl: boolean;
smtpUseDefaultCredentials: boolean;
defaultFromAddress: string;
defaultFromDisplayName: string;
}

2
npm/ng-packs/packages/setting-management/config/src/public-api.ts

@ -1,3 +1,5 @@
export * from './enums';
export * from './providers';
export * from './setting-management-config.module';
export * from './proxy';
export * from './components/email-setting-group/email-setting-group.component';

12
npm/ng-packs/packages/setting-management/config/src/setting-management-config.module.ts

@ -1,12 +1,20 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { CoreModule } from '@abp/ng.core';
import { EmailSettingGroupComponent } from './components/email-setting-group/email-setting-group.component';
import { SETTING_MANAGEMENT_ROUTE_PROVIDERS } from './providers/route.provider';
import { SETTING_MANAGEMENT_SETTING_TAB_PROVIDERS } from './providers/setting-tab.provider';
import { NgxValidateCoreModule } from '@ngx-validate/core';
@NgModule()
@NgModule({
imports: [CoreModule, NgxValidateCoreModule],
declarations: [EmailSettingGroupComponent],
exports: [EmailSettingGroupComponent],
})
export class SettingManagementConfigModule {
static forRoot(): ModuleWithProviders<SettingManagementConfigModule> {
return {
ngModule: SettingManagementConfigModule,
providers: [SETTING_MANAGEMENT_ROUTE_PROVIDERS],
providers: [SETTING_MANAGEMENT_ROUTE_PROVIDERS, SETTING_MANAGEMENT_SETTING_TAB_PROVIDERS],
};
}
}

4
npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts

@ -138,4 +138,8 @@ background-color: rgba(0, 0, 0, 0.6);
border-top: 1px solid #eee;
margin-top: -1px;
}
.breadcrumb {
background-color: transparent;
padding: 0.27rem;
}
`;

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs

@ -188,6 +188,7 @@ namespace MyCompanyName.MyProjectName
}
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
if (!env.IsDevelopment())
{

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs

@ -197,6 +197,7 @@ namespace MyCompanyName.MyProjectName
}
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
if (!env.IsDevelopment())
{

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs

@ -165,6 +165,7 @@ namespace MyCompanyName.MyProjectName
}
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
if (!env.IsDevelopment())
{

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs

@ -240,6 +240,7 @@ namespace MyCompanyName.MyProjectName.Web
}
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
if (!env.IsDevelopment())
{

1
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs

@ -215,6 +215,7 @@ namespace MyCompanyName.MyProjectName.Web
}
app.UseAbpRequestLocalization();
app.UseAbpSecurityHeaders();
if (!env.IsDevelopment())
{

Loading…
Cancel
Save