Browse Source

Merge branch 'dev' into cli-ConnectionStringProvider

pull/7340/head
Alper Ebicoglu 6 years ago
committed by GitHub
parent
commit
8048e7e7ee
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      common.props
  2. 103
      docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/POST.md
  3. BIN
      docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/example-result.png
  4. BIN
      docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/initial-project.png
  5. BIN
      docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/table-app-contract.png
  6. BIN
      docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/table-application.png
  7. BIN
      docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/table-web.png
  8. 4
      docs/en/UI/Angular/Testing.md
  9. 26
      framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
  10. 5
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHelper.cs
  11. 6
      framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs
  12. 2
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml
  13. 9
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogRepository.cs
  14. 26
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs
  15. 54
      modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs
  16. 5
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs
  17. 7
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs
  18. 11
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs
  19. 3
      modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Blogs/IBlogRepository.cs
  20. 11
      modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Comments/ICommentRepository.cs
  21. 9
      modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Posts/IPostRepository.cs
  22. 8
      modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/ITagRepository.cs
  23. 5
      modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Blogs/EfCoreBlogRepository.cs
  24. 17
      modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Comments/EfCoreCommentRepository.cs
  25. 19
      modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs
  26. 16
      modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs
  27. 5
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs
  28. 25
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs
  29. 23
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs
  30. 18
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs
  31. 4
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs
  32. 12
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListDto.cs
  33. 1
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs
  34. 16
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagCreateDto.cs
  35. 17
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagRemoveDto.cs
  36. 11
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs
  37. 3
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/ITagAdminAppService.cs
  38. 18
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/TagDefinitionDto.cs
  39. 5
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
  40. 3
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs
  41. 1
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs
  42. 52
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs
  43. 19
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs
  44. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs
  45. 6
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs
  46. 10
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs
  47. 1
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  48. 1
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json
  49. 22
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs
  50. 8
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitOptions.cs
  51. 32
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs
  52. 11
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/CmsKitTagOptions.cs
  53. 40
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs
  54. 26
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityNotTaggableException.cs
  55. 3
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTag.cs
  56. 52
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs
  57. 24
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagManager.cs
  58. 12
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs
  59. 15
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs
  60. 3
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagManager.cs
  61. 2
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagAlreadyExistException.cs
  62. 20
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitionDictionary.cs
  63. 31
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton1.cs
  64. 19
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagManager.cs
  65. 19
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs
  66. 2
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs
  67. 2
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs
  68. 19
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs
  69. 2
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/IPageAppService.cs
  70. 9
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PageAppService.cs
  71. 6
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs
  72. 5
      modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs
  73. 2
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml
  74. 11
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs
  75. 32
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/ContentViewComponent.cs
  76. 2
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/Default.cshtml
  77. 12
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/Default.cshtml
  78. 3
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs
  79. 11
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PagePublicAppService_Tests.cs
  80. 4
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagAdminAppService_Tests.cs
  81. 1
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/CmsKitDomainTestModule.cs
  82. 60
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/EntityTagManager_Tests.cs
  83. 30
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagManager_Tests.cs
  84. 59
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs
  85. 11
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs
  86. 9
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs
  87. 13
      modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs
  88. 15
      modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs
  89. 18
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs
  90. 26
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs
  91. 30
      modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs
  92. 11
      modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs
  93. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs
  94. 18
      modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingRepository.cs
  95. 29
      modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs
  96. 36
      modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs
  97. 75
      npm/ng-packs/packages/core/src/lib/tests/tree-utils.spec.ts
  98. 19
      npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts

2
common.props

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Version>4.3.0</Version> <Version>4.3.0</Version>
<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn> <NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl> <PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io/</PackageProjectUrl> <PackageProjectUrl>https://abp.io/</PackageProjectUrl>

103
docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/POST.md

@ -0,0 +1,103 @@
## Using MatBlazor UI Components With the ABP Framework
Hi, in this step by step article, I will show you how to integrate [MatBlazor](https://www.matblazor.com/), a blazor UI components into ABP Framework-based applications.
![example-result](example-result.png)
*(A screenshot from the example application developed in this article)*
## Create the Project
> First thing is to create the project. ABP Framework offers startup templates to get into business faster.
In this article, I will create a new startup template with EF Core as a database provider and Blazor for UI framework. But if you already have a project with Blazor UI, you don't need to create a new startup template, you can directly implement the following steps to your existing project.
> If you already have a project with the Blazor UI, you can skip this section.
* Before starting the development, we will create a new solution named `MatBlazorSample` (or whatever you want). We will create a new startup template with EF Core as a database provider and Blazor for UI framework by using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI):
````bash
abp new MatBlazorSample -u blazor
````
This will create new project inside of `aspnet-core`, so:
````bash
cd aspnet-core
````
and
````bash
dotnet restore
````
* Our project boilerplate will be ready after the download is finished. Then, we can open the solution in the Visual Studio (or any other IDE) and run the `MatBlazorSample.DbMigrator` to create the database and seed initial data (which creates the admin user, admin role, permissions etc.)
![initial-project](initial-project.png)
* After database and initial data created,
* Run the `MatBlazorSample.HttpApi.Host` to see our server side working and
* Run the `MatBlazorSample.Blazor` to see our UI working properly.
> _Default login credentials for admin: username is **admin** and password is **1q2w3E\***_
## Install MatBlazor
You can follow [this documentation](https://www.matblazor.com/) to install MatBlazor packages into your computer.
### Adding MatBlazor NuGet Packages
```bash
Install-Package MatBlazor
```
### Register MatBlazor Resources
1. Add the following line to the HEAD section of the `wwwroot/index.html` file within the `MatBlazorSample.Blazor` project:
```Razor
<head>
<!--...-->
<script src="_content/MatBlazor/dist/matBlazor.js"></script>
<link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet" />
</head>
```
2. In the `MatBlazorSampleBlazorModule` class, call the `AddMatBlazor()` method from your project's `ConfigureServices()` method:
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var environment = context.Services.GetSingletonInstance<IWebAssemblyHostEnvironment>();
var builder = context.Services.GetSingletonInstance<WebAssemblyHostBuilder>();
// ...
builder.Services.AddMatBlazor();
}
```
3. Register the **MatBlazorSample.Blazor** namespace in the `_Imports.razor` file:
```Razor
@using MatBlazor
```
## The Sample Application
We have created a sample application with [Table](https://www.matblazor.com/Table) example.
### The Source Code
You can download the source code from [here](https://github.com/abpframework/abp-samples/tree/master/MatBlazorSample).
The related files for this example are marked in the following screenshots.
![table-app-contract](table-app-contract.png)
![table-application](table-application.png)
![table-web](table-web.png)
## Conclusion
In this article, I've explained how to use [MatBlazor](https://www.matblazor.com/) components in your application. ABP Framework is designed so that it can work with any UI library/framework.

BIN
docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/example-result.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/initial-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/table-app-contract.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/table-application.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
docs/en/Community-Articles/2021-01-20-How-to-Integrate-the-MatBlazor-Blazor-Component/table-web.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

4
docs/en/UI/Angular/Testing.md

@ -374,3 +374,7 @@ Finally, don't forget to run your CI tests with the following command:
```sh ```sh
npm test -- --prod npm test -- --prod
``` ```
## See Also
* [ABP Community Video - Unit Testing with the Angular UI](https://community.abp.io/articles/unit-testing-with-the-angular-ui-p4l550q3)

26
framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs

@ -269,7 +269,7 @@ namespace Volo.Abp.BlazoriseUI
await GetEntitiesAsync(); await GetEntitiesAsync();
StateHasChanged(); await InvokeAsync(StateHasChanged);
} }
protected virtual async Task OnDataGridReadAsync(DataGridReadDataEventArgs<TListViewModel> e) protected virtual async Task OnDataGridReadAsync(DataGridReadDataEventArgs<TListViewModel> e)
@ -282,7 +282,7 @@ namespace Volo.Abp.BlazoriseUI
await GetEntitiesAsync(); await GetEntitiesAsync();
StateHasChanged(); await InvokeAsync(StateHasChanged);
} }
protected virtual async Task OpenCreateModalAsync() protected virtual async Task OpenCreateModalAsync()
@ -295,7 +295,7 @@ namespace Volo.Abp.BlazoriseUI
// Mapper will not notify Blazor that binded values are changed // Mapper will not notify Blazor that binded values are changed
// so we need to notify it manually by calling StateHasChanged // so we need to notify it manually by calling StateHasChanged
await InvokeAsync(() => StateHasChanged()); await InvokeAsync(StateHasChanged);
CreateModal.Show(); CreateModal.Show();
} }
@ -317,7 +317,7 @@ namespace Volo.Abp.BlazoriseUI
EditingEntityId = entity.Id; EditingEntityId = entity.Id;
EditingEntity = MapToEditingEntity(entityDto); EditingEntity = MapToEditingEntity(entityDto);
await InvokeAsync(() => StateHasChanged()); await InvokeAsync(StateHasChanged);
EditModal.Show(); EditModal.Show();
} }
@ -362,11 +362,8 @@ namespace Volo.Abp.BlazoriseUI
await CheckCreatePolicyAsync(); await CheckCreatePolicyAsync();
var createInput = MapToCreateInput(NewEntity); var createInput = MapToCreateInput(NewEntity);
await AppService.CreateAsync(createInput); await AppService.CreateAsync(createInput);
await GetEntitiesAsync();
await OnCreatedEntityAsync(); await OnCreatedEntityAsync();
CreateModal.Hide();
} }
} }
@ -375,9 +372,11 @@ namespace Volo.Abp.BlazoriseUI
return Task.CompletedTask; return Task.CompletedTask;
} }
protected virtual Task OnCreatedEntityAsync() protected virtual async Task OnCreatedEntityAsync()
{ {
return Task.CompletedTask; await GetEntitiesAsync();
CreateModal.Hide();
} }
protected virtual async Task UpdateEntityAsync() protected virtual async Task UpdateEntityAsync()
@ -389,11 +388,8 @@ namespace Volo.Abp.BlazoriseUI
await CheckUpdatePolicyAsync(); await CheckUpdatePolicyAsync();
var updateInput = MapToUpdateInput(EditingEntity); var updateInput = MapToUpdateInput(EditingEntity);
await AppService.UpdateAsync(EditingEntityId, updateInput); await AppService.UpdateAsync(EditingEntityId, updateInput);
await GetEntitiesAsync();
await OnUpdatedEntityAsync(); await OnUpdatedEntityAsync();
EditModal.Hide();
} }
} }
@ -402,9 +398,11 @@ namespace Volo.Abp.BlazoriseUI
return Task.CompletedTask; return Task.CompletedTask;
} }
protected virtual Task OnUpdatedEntityAsync() protected virtual async Task OnUpdatedEntityAsync()
{ {
return Task.CompletedTask; await GetEntitiesAsync();
EditModal.Hide();
} }
protected virtual async Task DeleteEntityAsync(TListViewModel entity) protected virtual async Task DeleteEntityAsync(TListViewModel entity)

5
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationHelper.cs

@ -4,7 +4,9 @@ namespace Volo.Abp.Validation
{ {
public class ValidationHelper public class ValidationHelper
{ {
private const string EmailRegEx = @"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"; // Taken from W3C as an alternative to the RFC5322 specification: https://html.spec.whatwg.org/#valid-e-mail-address
// The RFC5322 regex can be found here: https://emailregex.com/
public static string EmailRegEx { get; set; } = @"^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$";
public static bool IsValidEmailAddress(string email) public static bool IsValidEmailAddress(string email)
{ {
@ -13,7 +15,6 @@ namespace Volo.Abp.Validation
return false; return false;
} }
/*RFC 2822 (simplified)*/
return Regex.IsMatch(email, EmailRegEx, RegexOptions.Compiled | RegexOptions.IgnoreCase); return Regex.IsMatch(email, EmailRegEx, RegexOptions.Compiled | RegexOptions.IgnoreCase);
} }
} }

6
framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs

@ -180,15 +180,19 @@ namespace Volo.Abp.Validation
{ {
//Valid //Valid
ValidationHelper.IsValidEmailAddress("john.doe@domain.com").ShouldBe(true); ValidationHelper.IsValidEmailAddress("john.doe@domain.com").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("john-doe1@domain.co").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("ip@1.2.3.123").ShouldBe(true); ValidationHelper.IsValidEmailAddress("ip@1.2.3.123").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("pharaoh@egyptian.museum").ShouldBe(true); ValidationHelper.IsValidEmailAddress("pharaoh@egyptian.museum").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("john.doe+regexbuddy@gmail.com").ShouldBe(true); ValidationHelper.IsValidEmailAddress("john.doe+regexbuddy@gmail.com").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("Mike.O'Dell@ireland.com").ShouldBe(true); ValidationHelper.IsValidEmailAddress("Mike.O'Dell@ireland.com").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("admin@localhost").ShouldBe(true);
ValidationHelper.IsValidEmailAddress("j@h.c").ShouldBe(true);
//Invalid //Invalid
ValidationHelper.IsValidEmailAddress("1024x768@60Hz").ShouldBe(false);
ValidationHelper.IsValidEmailAddress("not.a.valid.email").ShouldBe(false); ValidationHelper.IsValidEmailAddress("not.a.valid.email").ShouldBe(false);
ValidationHelper.IsValidEmailAddress("john@aol...com").ShouldBe(false); ValidationHelper.IsValidEmailAddress("john@aol...com").ShouldBe(false);
ValidationHelper.IsValidEmailAddress("john@aol@domain.com").ShouldBe(false);
ValidationHelper.IsValidEmailAddress("jack@domain.").ShouldBe(false);
} }
[DependsOn(typeof(AbpAutofacModule))] [DependsOn(typeof(AbpAutofacModule))]

2
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml

@ -56,7 +56,7 @@
<input asp-for="ReturnUrlHash"/> <input asp-for="ReturnUrlHash"/>
@foreach (var provider in Model.VisibleExternalProviders) @foreach (var provider in Model.VisibleExternalProviders)
{ {
<button type="submit" class="btn btn-primary m-1" name="provider" value="@provider.AuthenticationScheme" title="@L["GivenTenantIsNotAvailable", provider.DisplayName]">@provider.DisplayName</button> <button type="submit" class="btn btn-primary m-1" name="provider" value="@provider.AuthenticationScheme" title="@L["LogInUsingYourProviderAccount", provider.DisplayName]">@provider.DisplayName</button>
} }
</form> </form>
</div> </div>

9
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogRepository.cs

@ -44,9 +44,10 @@ namespace Volo.Abp.AuditLogging
Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync( Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(
DateTime startDate, DateTime startDate,
DateTime endDate); DateTime endDate,
CancellationToken cancellationToken = default);
Task<EntityChange> GetEntityChange(Guid entityChangeId); Task<EntityChange> GetEntityChange(Guid entityChangeId, CancellationToken cancellationToken = default);
Task<List<EntityChange>> GetEntityChangeListAsync( Task<List<EntityChange>> GetEntityChangeListAsync(
string sorting = null, string sorting = null,
@ -70,8 +71,8 @@ namespace Volo.Abp.AuditLogging
string entityTypeFullName = null, string entityTypeFullName = null,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(Guid entityChangeId); Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(Guid entityChangeId, CancellationToken cancellationToken = default);
Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(string entityId, string entityTypeFullName); Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(string entityId, string entityTypeFullName, CancellationToken cancellationToken = default);
} }
} }

26
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs

@ -125,14 +125,17 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
.WhereIf(minExecutionDuration != null && minExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration >= minExecutionDuration); .WhereIf(minExecutionDuration != null && minExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration >= minExecutionDuration);
} }
public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(DateTime startDate, DateTime endDate) public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(
DateTime startDate,
DateTime endDate,
CancellationToken cancellationToken = default)
{ {
var result = await (await GetDbSetAsync()).AsNoTracking() var result = await (await GetDbSetAsync()).AsNoTracking()
.Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate) .Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate)
.OrderBy(t => t.ExecutionTime) .OrderBy(t => t.ExecutionTime)
.GroupBy(t => new { t.ExecutionTime.Date }) .GroupBy(t => new { t.ExecutionTime.Date })
.Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) }) .Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) })
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime); return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime);
} }
@ -148,14 +151,16 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
return (await GetQueryableAsync()).IncludeDetails(); return (await GetQueryableAsync()).IncludeDetails();
} }
public virtual async Task<EntityChange> GetEntityChange(Guid entityChangeId) public virtual async Task<EntityChange> GetEntityChange(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{ {
var entityChange = await (await GetDbContextAsync()).Set<EntityChange>() var entityChange = await (await GetDbContextAsync()).Set<EntityChange>()
.AsNoTracking() .AsNoTracking()
.IncludeDetails() .IncludeDetails()
.Where(x => x.Id == entityChangeId) .Where(x => x.Id == entityChangeId)
.OrderBy(x => x.Id) .OrderBy(x => x.Id)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
if (entityChange == null) if (entityChange == null)
{ {
@ -201,10 +206,12 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
return totalCount; return totalCount;
} }
public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(Guid entityChangeId) public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{ {
var auditLog = await (await GetDbSetAsync()).AsNoTracking().IncludeDetails() var auditLog = await (await GetDbSetAsync()).AsNoTracking().IncludeDetails()
.Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)).FirstAsync(); .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)).FirstAsync(GetCancellationToken(cancellationToken));
return new EntityChangeWithUsername() return new EntityChangeWithUsername()
{ {
@ -213,7 +220,10 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
}; };
} }
public virtual async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(string entityId, string entityTypeFullName) public virtual async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(
string entityId,
string entityTypeFullName,
CancellationToken cancellationToken = default)
{ {
var dbContext = await GetDbContextAsync(); var dbContext = await GetDbContextAsync();
@ -225,7 +235,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
return await (from e in query return await (from e in query
join auditLog in dbContext.AuditLogs on e.AuditLogId equals auditLog.Id join auditLog in dbContext.AuditLogs on e.AuditLogId equals auditLog.Id
select new EntityChangeWithUsername {EntityChange = e, UserName = auditLog.UserName}) select new EntityChangeWithUsername {EntityChange = e, UserName = auditLog.UserName})
.OrderByDescending(x => x.EntityChange.ChangeTime).ToListAsync(); .OrderByDescending(x => x.EntityChange.ChangeTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
protected virtual async Task<IQueryable<EntityChange>> GetEntityChangeListQueryAsync( protected virtual async Task<IQueryable<EntityChange>> GetEntityChangeListQueryAsync(

54
modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs

@ -52,7 +52,8 @@ namespace Volo.Abp.AuditLogging.MongoDB
minDuration, minDuration,
hasException, hasException,
httpStatusCode, httpStatusCode,
includeDetails includeDetails,
cancellationToken
); );
return await query.OrderBy(sorting ?? "executionTime desc").As<IMongoQueryable<AuditLog>>() return await query.OrderBy(sorting ?? "executionTime desc").As<IMongoQueryable<AuditLog>>()
@ -85,7 +86,8 @@ namespace Volo.Abp.AuditLogging.MongoDB
maxDuration, maxDuration,
minDuration, minDuration,
hasException, hasException,
httpStatusCode httpStatusCode,
cancellationToken: cancellationToken
); );
var count = await query.As<IMongoQueryable<AuditLog>>() var count = await query.As<IMongoQueryable<AuditLog>>()
@ -106,9 +108,10 @@ namespace Volo.Abp.AuditLogging.MongoDB
int? minDuration = null, int? minDuration = null,
bool? hasException = null, bool? hasException = null,
HttpStatusCode? httpStatusCode = null, HttpStatusCode? httpStatusCode = null,
bool includeDetails = false) bool includeDetails = false,
CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync()) return (await GetMongoQueryableAsync(cancellationToken))
.WhereIf(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime) .WhereIf(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime)
.WhereIf(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime) .WhereIf(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime)
.WhereIf(hasException.HasValue && hasException.Value, auditLog => auditLog.Exceptions != null && auditLog.Exceptions != "") .WhereIf(hasException.HasValue && hasException.Value, auditLog => auditLog.Exceptions != null && auditLog.Exceptions != "")
@ -124,9 +127,12 @@ namespace Volo.Abp.AuditLogging.MongoDB
} }
public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(DateTime startDate, DateTime endDate) public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(
DateTime startDate,
DateTime endDate,
CancellationToken cancellationToken = default)
{ {
var result = await (await GetMongoQueryableAsync()) var result = await (await GetMongoQueryableAsync(cancellationToken))
.Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate) .Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate)
.OrderBy(t => t.ExecutionTime) .OrderBy(t => t.ExecutionTime)
.GroupBy(t => new .GroupBy(t => new
@ -136,17 +142,19 @@ namespace Volo.Abp.AuditLogging.MongoDB
t.ExecutionTime.Day t.ExecutionTime.Day
}) })
.Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) }) .Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) })
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime); return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime);
} }
public virtual async Task<EntityChange> GetEntityChange(Guid entityChangeId) public virtual async Task<EntityChange> GetEntityChange(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{ {
var entityChange = (await (await GetMongoQueryableAsync()) var entityChange = (await (await GetMongoQueryableAsync(cancellationToken))
.Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)) .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId))
.OrderBy(x => x.Id) .OrderBy(x => x.Id)
.FirstAsync()).EntityChanges.FirstOrDefault(x => x.Id == entityChangeId); .FirstAsync(GetCancellationToken(cancellationToken))).EntityChanges.FirstOrDefault(x => x.Id == entityChangeId);
if (entityChange == null) if (entityChange == null)
{ {
@ -169,7 +177,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
bool includeDetails = false, bool includeDetails = false,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, cancellationToken);
return await query return await query
.OrderBy(sorting ?? "changeTime desc") .OrderBy(sorting ?? "changeTime desc")
@ -187,18 +195,20 @@ namespace Volo.Abp.AuditLogging.MongoDB
string entityTypeFullName = null, string entityTypeFullName = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, cancellationToken);
var count = await query.As<IMongoQueryable<EntityChange>>().LongCountAsync(GetCancellationToken(cancellationToken)); var count = await query.As<IMongoQueryable<EntityChange>>().LongCountAsync(GetCancellationToken(cancellationToken));
return count; return count;
} }
public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(Guid entityChangeId) public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{ {
var auditLog = (await (await GetMongoQueryableAsync()) var auditLog = await (await GetMongoQueryableAsync(cancellationToken))
.Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)) .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId))
.FirstAsync()); .FirstAsync(GetCancellationToken(cancellationToken));
return new EntityChangeWithUsername() return new EntityChangeWithUsername()
{ {
@ -207,13 +217,16 @@ namespace Volo.Abp.AuditLogging.MongoDB
}; };
} }
public virtual async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(string entityId, string entityTypeFullName) public virtual async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(
string entityId,
string entityTypeFullName,
CancellationToken cancellationToken = default)
{ {
var auditLogs = await (await GetMongoQueryableAsync()) var auditLogs = await (await GetMongoQueryableAsync(cancellationToken))
.Where(x => x.EntityChanges.Any(y => y.EntityId == entityId && y.EntityTypeFullName == entityTypeFullName)) .Where(x => x.EntityChanges.Any(y => y.EntityId == entityId && y.EntityTypeFullName == entityTypeFullName))
.As<IMongoQueryable<AuditLog>>() .As<IMongoQueryable<AuditLog>>()
.OrderByDescending(x => x.ExecutionTime) .OrderByDescending(x => x.ExecutionTime)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
var entityChanges = auditLogs.SelectMany(x => x.EntityChanges).ToList(); var entityChanges = auditLogs.SelectMany(x => x.EntityChanges).ToList();
@ -229,9 +242,10 @@ namespace Volo.Abp.AuditLogging.MongoDB
DateTime? endTime = null, DateTime? endTime = null,
EntityChangeType? changeType = null, EntityChangeType? changeType = null,
string entityId = null, string entityId = null,
string entityTypeFullName = null) string entityTypeFullName = null,
CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync()) return (await GetMongoQueryableAsync(cancellationToken))
.SelectMany(x => x.EntityChanges) .SelectMany(x => x.EntityChanges)
.WhereIf(auditLogId.HasValue, e => e.Id == auditLogId) .WhereIf(auditLogId.HasValue, e => e.Id == auditLogId)
.WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime) .WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime)

5
modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/IBackgroundJobRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -7,6 +8,6 @@ namespace Volo.Abp.BackgroundJobs
{ {
public interface IBackgroundJobRepository : IBasicRepository<BackgroundJobRecord, Guid> public interface IBackgroundJobRepository : IBasicRepository<BackgroundJobRecord, Guid>
{ {
Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount); Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount, CancellationToken cancellationToken = default);
} }
} }

7
modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
@ -21,9 +22,11 @@ namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore
Clock = clock; Clock = clock;
} }
public virtual async Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount) public virtual async Task<List<BackgroundJobRecord>> GetWaitingListAsync(
int maxResultCount,
CancellationToken cancellationToken = default)
{ {
return await (await GetWaitingListQueryAsync(maxResultCount)).ToListAsync(); return await (await GetWaitingListQueryAsync(maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken));
} }
protected virtual async Task<IQueryable<BackgroundJobRecord>> GetWaitingListQueryAsync(int maxResultCount) protected virtual async Task<IQueryable<BackgroundJobRecord>> GetWaitingListQueryAsync(int maxResultCount)

11
modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
@ -21,15 +22,17 @@ namespace Volo.Abp.BackgroundJobs.MongoDB
Clock = clock; Clock = clock;
} }
public virtual async Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount) public virtual async Task<List<BackgroundJobRecord>> GetWaitingListAsync(
int maxResultCount,
CancellationToken cancellationToken = default)
{ {
return await (await GetWaitingListQuery(maxResultCount)).ToListAsync(); return await (await GetWaitingListQuery(maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken));
} }
protected virtual async Task<IMongoQueryable<BackgroundJobRecord>> GetWaitingListQuery(int maxResultCount) protected virtual async Task<IMongoQueryable<BackgroundJobRecord>> GetWaitingListQuery(int maxResultCount, CancellationToken cancellationToken = default)
{ {
var now = Clock.Now; var now = Clock.Now;
return (await GetMongoQueryableAsync()) return (await GetMongoQueryableAsync(cancellationToken))
.Where(t => !t.IsAbandoned && t.NextTryTime <= now) .Where(t => !t.IsAbandoned && t.NextTryTime <= now)
.OrderByDescending(t => t.Priority) .OrderByDescending(t => t.Priority)
.ThenBy(t => t.TryCount) .ThenBy(t => t.TryCount)

3
modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Blogs/IBlogRepository.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -6,6 +7,6 @@ namespace Volo.Blogging.Blogs
{ {
public interface IBlogRepository : IBasicRepository<Blog, Guid> public interface IBlogRepository : IBasicRepository<Blog, Guid>
{ {
Task<Blog> FindByShortNameAsync(string shortName); Task<Blog> FindByShortNameAsync(string shortName, CancellationToken cancellationToken = default);
} }
} }

11
modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Comments/ICommentRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -7,14 +8,12 @@ namespace Volo.Blogging.Comments
{ {
public interface ICommentRepository : IBasicRepository<Comment, Guid> public interface ICommentRepository : IBasicRepository<Comment, Guid>
{ {
Task<List<Comment>> GetListOfPostAsync( Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default);
Guid postId
);
Task<int> GetCommentCountOfPostAsync(Guid postId); Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default);
Task<List<Comment>> GetRepliesOfComment(Guid id); Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default);
Task DeleteOfPost(Guid id); Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default);
} }
} }

9
modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Posts/IPostRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -7,12 +8,12 @@ namespace Volo.Blogging.Posts
{ {
public interface IPostRepository : IBasicRepository<Post, Guid> public interface IPostRepository : IBasicRepository<Post, Guid>
{ {
Task<List<Post>> GetPostsByBlogId(Guid id); Task<List<Post>> GetPostsByBlogId(Guid id, CancellationToken cancellationToken = default);
Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null); Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null, CancellationToken cancellationToken = default);
Task<Post> GetPostByUrl(Guid blogId, string url); Task<Post> GetPostByUrl(Guid blogId, string url, CancellationToken cancellationToken = default);
Task<List<Post>> GetOrderedList(Guid blogId,bool descending = false); Task<List<Post>> GetOrderedList(Guid blogId,bool descending = false, CancellationToken cancellationToken = default);
} }
} }

8
modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Tagging/ITagRepository.cs

@ -8,13 +8,13 @@ namespace Volo.Blogging.Tagging
{ {
public interface ITagRepository : IBasicRepository<Tag, Guid> public interface ITagRepository : IBasicRepository<Tag, Guid>
{ {
Task<List<Tag>> GetListAsync(Guid blogId); Task<List<Tag>> GetListAsync(Guid blogId, CancellationToken cancellationToken = default);
Task<Tag> GetByNameAsync(Guid blogId, string name); Task<Tag> GetByNameAsync(Guid blogId, string name, CancellationToken cancellationToken = default);
Task<Tag> FindByNameAsync(Guid blogId, string name); Task<Tag> FindByNameAsync(Guid blogId, string name, CancellationToken cancellationToken = default);
Task<List<Tag>> GetListAsync(IEnumerable<Guid> ids); Task<List<Tag>> GetListAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default);
Task DecreaseUsageCountOfTagsAsync(List<Guid> id, CancellationToken cancellationToken = default); Task DecreaseUsageCountOfTagsAsync(List<Guid> id, CancellationToken cancellationToken = default);
} }

5
modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Blogs/EfCoreBlogRepository.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
@ -15,9 +16,9 @@ namespace Volo.Blogging.Blogs
} }
public async Task<Blog> FindByShortNameAsync(string shortName) public async Task<Blog> FindByShortNameAsync(string shortName, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.ShortName == shortName); return await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.ShortName == shortName, GetCancellationToken(cancellationToken));
} }
} }
} }

17
modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Comments/EfCoreCommentRepository.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
@ -16,29 +17,29 @@ namespace Volo.Blogging.Comments
{ {
} }
public async Task<List<Comment>> GetListOfPostAsync(Guid postId) public async Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.Where(a => a.PostId == postId) .Where(a => a.PostId == postId)
.OrderBy(a => a.CreationTime) .OrderBy(a => a.CreationTime)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<int> GetCommentCountOfPostAsync(Guid postId) public async Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.CountAsync(a => a.PostId == postId); .CountAsync(a => a.PostId == postId, GetCancellationToken(cancellationToken));
} }
public async Task<List<Comment>> GetRepliesOfComment(Guid id) public async Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.Where(a => a.RepliedCommentId == id).ToListAsync(); .Where(a => a.RepliedCommentId == id).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task DeleteOfPost(Guid id) public async Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default)
{ {
var recordsToDelete = (await GetDbSetAsync()).Where(pt => pt.PostId == id); var recordsToDelete = await (await GetDbSetAsync()).Where(pt => pt.PostId == id).ToListAsync(GetCancellationToken(cancellationToken));
(await GetDbSetAsync()).RemoveRange(recordsToDelete); (await GetDbSetAsync()).RemoveRange(recordsToDelete);
} }
} }

19
modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
@ -18,12 +19,12 @@ namespace Volo.Blogging.Posts
} }
public async Task<List<Post>> GetPostsByBlogId(Guid id) public async Task<List<Post>> GetPostsByBlogId(Guid id, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()).Where(p => p.BlogId == id).OrderByDescending(p=>p.CreationTime).ToListAsync(); return await (await GetDbSetAsync()).Where(p => p.BlogId == id).OrderByDescending(p=>p.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null) public async Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null, CancellationToken cancellationToken = default)
{ {
var query = (await GetDbSetAsync()).Where(p => blogId == p.BlogId && p.Url == url); var query = (await GetDbSetAsync()).Where(p => blogId == p.BlogId && p.Url == url);
@ -32,12 +33,12 @@ namespace Volo.Blogging.Posts
query = query.Where(p => excludingPostId != p.Id); query = query.Where(p => excludingPostId != p.Id);
} }
return await query.AnyAsync(); return await query.AnyAsync(GetCancellationToken(cancellationToken));
} }
public async Task<Post> GetPostByUrl(Guid blogId, string url) public async Task<Post> GetPostByUrl(Guid blogId, string url, CancellationToken cancellationToken = default)
{ {
var post = await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url); var post = await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url, GetCancellationToken(cancellationToken));
if (post == null) if (post == null)
{ {
@ -47,15 +48,15 @@ namespace Volo.Blogging.Posts
return post; return post;
} }
public async Task<List<Post>> GetOrderedList(Guid blogId,bool descending = false) public async Task<List<Post>> GetOrderedList(Guid blogId,bool descending = false, CancellationToken cancellationToken = default)
{ {
if (!descending) if (!descending)
{ {
return await (await GetDbSetAsync()).Where(x=>x.BlogId==blogId).OrderByDescending(x => x.CreationTime).ToListAsync(); return await (await GetDbSetAsync()).Where(x=>x.BlogId==blogId).OrderByDescending(x => x.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
else else
{ {
return await (await GetDbSetAsync()).Where(x => x.BlogId == blogId).OrderBy(x => x.CreationTime).ToListAsync(); return await (await GetDbSetAsync()).Where(x => x.BlogId == blogId).OrderBy(x => x.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
} }

16
modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs

@ -17,24 +17,24 @@ namespace Volo.Blogging.Tagging
{ {
} }
public async Task<List<Tag>> GetListAsync(Guid blogId) public async Task<List<Tag>> GetListAsync(Guid blogId, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()).Where(t=>t.BlogId == blogId).ToListAsync(); return await (await GetDbSetAsync()).Where(t=>t.BlogId == blogId).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<Tag> GetByNameAsync(Guid blogId, string name) public async Task<Tag> GetByNameAsync(Guid blogId, string name, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()).FirstAsync(t=> t.BlogId == blogId && t.Name == name); return await (await GetDbSetAsync()).FirstAsync(t=> t.BlogId == blogId && t.Name == name, GetCancellationToken(cancellationToken));
} }
public async Task<Tag> FindByNameAsync(Guid blogId, string name) public async Task<Tag> FindByNameAsync(Guid blogId, string name, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()).FirstOrDefaultAsync(t => t.BlogId == blogId && t.Name == name); return await (await GetDbSetAsync()).FirstOrDefaultAsync(t => t.BlogId == blogId && t.Name == name, GetCancellationToken(cancellationToken));
} }
public async Task<List<Tag>> GetListAsync(IEnumerable<Guid> ids) public async Task<List<Tag>> GetListAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()).Where(t => ids.Contains(t.Id)).ToListAsync(); return await (await GetDbSetAsync()).Where(t => ids.Contains(t.Id)).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task DecreaseUsageCountOfTagsAsync(List<Guid> ids, CancellationToken cancellationToken = default) public async Task DecreaseUsageCountOfTagsAsync(List<Guid> ids, CancellationToken cancellationToken = default)

5
modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.Domain.Repositories.MongoDB;
@ -13,9 +14,9 @@ namespace Volo.Blogging.Blogs
{ {
} }
public async Task<Blog> FindByShortNameAsync(string shortName) public async Task<Blog> FindByShortNameAsync(string shortName, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).FirstOrDefaultAsync(p => p.ShortName == shortName); return await (await GetMongoQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.ShortName == shortName, GetCancellationToken(cancellationToken));
} }
} }
} }

25
modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
@ -15,33 +16,33 @@ namespace Volo.Blogging.Comments
{ {
} }
public async Task<List<Comment>> GetListOfPostAsync(Guid postId) public async Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.Where(a => a.PostId == postId) .Where(a => a.PostId == postId)
.OrderBy(a => a.CreationTime) .OrderBy(a => a.CreationTime)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<int> GetCommentCountOfPostAsync(Guid postId) public async Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.CountAsync(a => a.PostId == postId); .CountAsync(a => a.PostId == postId, GetCancellationToken(cancellationToken));
} }
public async Task<List<Comment>> GetRepliesOfComment(Guid id) public async Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.Where(a => a.RepliedCommentId == id).ToListAsync(); .Where(a => a.RepliedCommentId == id).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task DeleteOfPost(Guid id) public async Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default)
{ {
var recordsToDelete = (await GetMongoQueryableAsync()).Where(pt => pt.PostId == id); var recordsToDelete = (await GetMongoQueryableAsync(cancellationToken)).Where(pt => pt.PostId == id);
foreach (var record in recordsToDelete) foreach (var record in recordsToDelete)
{ {
await DeleteAsync(record); await DeleteAsync(record, cancellationToken: GetCancellationToken(cancellationToken));
} }
} }
} }

23
modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
@ -16,27 +17,27 @@ namespace Volo.Blogging.Posts
{ {
} }
public async Task<List<Post>> GetPostsByBlogId(Guid id) public async Task<List<Post>> GetPostsByBlogId(Guid id, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).Where(p => p.BlogId == id).OrderByDescending(p => p.CreationTime).ToListAsync(); return await (await GetMongoQueryableAsync(cancellationToken)).Where(p => p.BlogId == id).OrderByDescending(p => p.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null) public async Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null, CancellationToken cancellationToken = default)
{ {
var query = (await GetMongoQueryableAsync()).Where(p => blogId == p.BlogId && p.Url == url); var query = (await GetMongoQueryableAsync(cancellationToken)).Where(p => blogId == p.BlogId && p.Url == url);
if (excludingPostId != null) if (excludingPostId != null)
{ {
query = query.Where(p => excludingPostId != p.Id); query = query.Where(p => excludingPostId != p.Id);
} }
return await query.AnyAsync(); return await query.AnyAsync(GetCancellationToken(cancellationToken));
} }
public async Task<Post> GetPostByUrl(Guid blogId, string url) public async Task<Post> GetPostByUrl(Guid blogId, string url, CancellationToken cancellationToken = default)
{ {
var post = await (await GetMongoQueryableAsync()).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url); var post = await (await GetMongoQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url, GetCancellationToken(cancellationToken));
if (post == null) if (post == null)
{ {
@ -46,16 +47,16 @@ namespace Volo.Blogging.Posts
return post; return post;
} }
public async Task<List<Post>> GetOrderedList(Guid blogId, bool @descending = false) public async Task<List<Post>> GetOrderedList(Guid blogId, bool @descending = false, CancellationToken cancellationToken = default)
{ {
var query = (await GetMongoQueryableAsync()).Where(x => x.BlogId == blogId); var query = (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.BlogId == blogId);
if (!descending) if (!descending)
{ {
return await query.OrderBy(x => x.CreationTime).ToListAsync(); return await query.OrderBy(x => x.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
return await query.OrderByDescending(x => x.CreationTime).ToListAsync(); return await query.OrderByDescending(x => x.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
} }
} }

18
modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs

@ -18,29 +18,29 @@ namespace Volo.Blogging.Tagging
{ {
} }
public async Task<List<Tag>> GetListAsync(Guid blogId) public async Task<List<Tag>> GetListAsync(Guid blogId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).Where(t => t.BlogId == blogId).ToListAsync(); return await (await GetMongoQueryableAsync(cancellationToken)).Where(t => t.BlogId == blogId).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task<Tag> GetByNameAsync(Guid blogId, string name) public async Task<Tag> GetByNameAsync(Guid blogId, string name, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).Where(t => t.BlogId == blogId && t.Name == name).FirstAsync(); return await (await GetMongoQueryableAsync(cancellationToken)).Where(t => t.BlogId == blogId && t.Name == name).FirstAsync(GetCancellationToken(cancellationToken));
} }
public async Task<Tag> FindByNameAsync(Guid blogId, string name) public async Task<Tag> FindByNameAsync(Guid blogId, string name, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).Where(t => t.BlogId == blogId && t.Name == name).FirstOrDefaultAsync(); return await (await GetMongoQueryableAsync(cancellationToken)).Where(t => t.BlogId == blogId && t.Name == name).FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
} }
public async Task<List<Tag>> GetListAsync(IEnumerable<Guid> ids) public async Task<List<Tag>> GetListAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).Where(t => ids.Contains(t.Id)).ToListAsync(); return await (await GetMongoQueryableAsync(cancellationToken)).Where(t => ids.Contains(t.Id)).ToListAsync(GetCancellationToken(cancellationToken));
} }
public async Task DecreaseUsageCountOfTagsAsync(List<Guid> ids, CancellationToken cancellationToken = default) public async Task DecreaseUsageCountOfTagsAsync(List<Guid> ids, CancellationToken cancellationToken = default)
{ {
var tags = await (await GetMongoQueryableAsync()) var tags = await (await GetMongoQueryableAsync(cancellationToken))
.Where(t => ids.Contains(t.Id)) .Where(t => ids.Contains(t.Id))
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));

4
modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs

@ -15,7 +15,7 @@ namespace Volo.Blogging.Users
{ {
} }
public async Task<List<BlogUser>> GetUsersAsync(int maxCount, string filter, CancellationToken cancellationToken) public async Task<List<BlogUser>> GetUsersAsync(int maxCount, string filter, CancellationToken cancellationToken = default)
{ {
var query = await GetMongoQueryableAsync(cancellationToken); var query = await GetMongoQueryableAsync(cancellationToken);
@ -24,7 +24,7 @@ namespace Volo.Blogging.Users
query = query.Where(x => x.UserName.Contains(filter)); query = query.Where(x => x.UserName.Contains(filter));
} }
return await query.Take(maxCount).ToListAsync(cancellationToken); return await query.Take(maxCount).ToListAsync(GetCancellationToken(cancellationToken));
} }
} }
} }

12
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListDto.cs

@ -0,0 +1,12 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Volo.CmsKit.Admin.Contents
{
public class ContentGetListDto : EntityDto<Guid>
{
public string EntityType { get; set; }
public string EntityId { get; set; }
}
}

1
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs

@ -7,6 +7,7 @@ namespace Volo.CmsKit.Admin.Contents
public interface IContentAdminAppService public interface IContentAdminAppService
: ICrudAppService< : ICrudAppService<
ContentDto, ContentDto,
ContentGetListDto,
Guid, Guid,
ContentGetListInput, ContentGetListInput,
ContentCreateDto, ContentCreateDto,

16
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagCreateDto.cs

@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
namespace Volo.CmsKit.Admin.Tags
{
public class EntityTagCreateDto
{
[Required]
public string TagName { get; set; }
[Required]
public string EntityType { get; set; }
[Required]
public string EntityId { get; set; }
}
}

17
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagRemoveDto.cs

@ -0,0 +1,17 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Volo.CmsKit.Admin.Tags
{
public class EntityTagRemoveDto
{
[Required]
public Guid TagId { get; set; }
[Required]
public string EntityType { get; set; }
[Required]
public string EntityId { get; set; }
}
}

11
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/IEntityTagAdminAppService.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Volo.CmsKit.Admin.Tags
{
public interface IEntityTagAdminAppService
{
Task AddTagToEntityAsync(EntityTagCreateDto input);
Task RemoveTagFromEntityAsync(EntityTagRemoveDto input);
}
}

3
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/ITagAdminAppService.cs

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.CmsKit.Tags; using Volo.CmsKit.Tags;
@ -6,5 +8,6 @@ namespace Volo.CmsKit.Admin.Tags
{ {
public interface ITagAdminAppService : ICrudAppService<TagDto, Guid, TagGetListInput, TagCreateDto, TagUpdateDto> public interface ITagAdminAppService : ICrudAppService<TagDto, Guid, TagGetListInput, TagCreateDto, TagUpdateDto>
{ {
Task<List<TagDefinitionDto>> GetTagDefinitionsAsync();
} }
} }

18
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/TagDefinitionDto.cs

@ -0,0 +1,18 @@
namespace Volo.CmsKit.Admin.Tags
{
public class TagDefinitionDto
{
public TagDefinitionDto()
{
}
public TagDefinitionDto(string entityType, string displayName)
{
EntityType = entityType;
DisplayName = displayName;
}
public string EntityType { get; set; }
public string DisplayName { get; set; }
}
}

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

@ -1,8 +1,10 @@
using AutoMapper; using AutoMapper;
using Volo.CmsKit.Admin.Contents; using Volo.CmsKit.Admin.Contents;
using Volo.CmsKit.Admin.Pages; using Volo.CmsKit.Admin.Pages;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Contents; using Volo.CmsKit.Contents;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit.Admin namespace Volo.CmsKit.Admin
{ {
@ -13,8 +15,11 @@ namespace Volo.CmsKit.Admin
CreateMap<Page, PageDto>(); CreateMap<Page, PageDto>();
CreateMap<Content, ContentDto>(MemberList.Destination); CreateMap<Content, ContentDto>(MemberList.Destination);
CreateMap<Content, ContentGetListDto>(MemberList.Destination);
CreateMap<ContentCreateDto, Content>(MemberList.Source); CreateMap<ContentCreateDto, Content>(MemberList.Source);
CreateMap<ContentUpdateDto, Content>(MemberList.Source); CreateMap<ContentUpdateDto, Content>(MemberList.Source);
CreateMap<TagEntityTypeDefiniton, TagDefinitionDto>(MemberList.Destination);
} }
} }
} }

3
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs

@ -14,6 +14,7 @@ namespace Volo.CmsKit.Admin.Contents
CrudAppService< CrudAppService<
Content, Content,
ContentDto, ContentDto,
ContentGetListDto,
Guid, Guid,
ContentGetListInput, ContentGetListInput,
ContentCreateDto, ContentCreateDto,
@ -51,7 +52,7 @@ namespace Volo.CmsKit.Admin.Contents
await ContentManager.InsertAsync(entity); await ContentManager.InsertAsync(entity);
return MapToGetListOutputDto(entity); return MapToGetOutputDto(entity);
} }
} }
} }

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

@ -24,7 +24,6 @@ namespace Volo.CmsKit.Admin.Pages
public virtual async Task<PageDto> GetAsync(Guid id) public virtual async Task<PageDto> GetAsync(Guid id)
{ {
var page = await PageRepository.GetAsync(id); var page = await PageRepository.GetAsync(id);
return ObjectMapper.Map<Page, PageDto>(page); return ObjectMapper.Map<Page, PageDto>(page);
} }

52
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs

@ -0,0 +1,52 @@
using System;
using System.Threading.Tasks;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit.Admin.Application.Volo.CmsKit.Admin.Tags
{
public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService
{
protected ITagDefinitionStore _tagDefinitionStore;
protected IEntityTagManager _entityTagManager;
protected ITagManager _tagManager;
public EntityTagAdminAppService(
ITagDefinitionStore tagDefinitionStore,
IEntityTagManager entityTagManager,
ITagManager tagManager)
{
_tagDefinitionStore = tagDefinitionStore;
_entityTagManager = entityTagManager;
_tagManager = tagManager;
}
public async Task AddTagToEntityAsync(EntityTagCreateDto input)
{
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
await CheckPolicyAsync(definition.CreatePolicy);
var tag = await _tagManager.GetOrAddAsync(input.EntityType, input.TagName, CurrentTenant?.Id);
await _entityTagManager.AddTagToEntityAsync(
tag.Id,
input.EntityType,
input.EntityId,
CurrentTenant?.Id);
}
public async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input)
{
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
await CheckPolicyAsync(definition.DeletePolicy);
await _entityTagManager.RemoveTagFromEntityAsync(
input.TagId,
input.EntityType,
input.EntityId,
CurrentTenant?.Id);
}
}
}

19
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs

@ -1,12 +1,11 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Permissions; using Volo.CmsKit.Permissions;
using Volo.CmsKit.Tags; using Volo.CmsKit.Tags;
@ -25,11 +24,15 @@ namespace Volo.CmsKit.Admin.Tags
{ {
protected ITagManager TagManager { get; } protected ITagManager TagManager { get; }
protected IStringLocalizerFactory StringLocalizerFactory { get; }
public TagAdminAppService( public TagAdminAppService(
IRepository<Tag, Guid> repository, IRepository<Tag, Guid> repository,
ITagManager tagManager) : base(repository) ITagManager tagManager,
IStringLocalizerFactory stringLocalizerFactory) : base(repository)
{ {
TagManager = tagManager; TagManager = tagManager;
StringLocalizerFactory = stringLocalizerFactory;
GetListPolicyName = CmsKitAdminPermissions.Tags.Default; GetListPolicyName = CmsKitAdminPermissions.Tags.Default;
GetPolicyName = CmsKitAdminPermissions.Tags.Default; GetPolicyName = CmsKitAdminPermissions.Tags.Default;
@ -68,5 +71,15 @@ namespace Volo.CmsKit.Admin.Tags
x.Name.ToLower().Contains(input.Filter) || x.Name.ToLower().Contains(input.Filter) ||
x.EntityType.ToLower().Contains(input.Filter)); x.EntityType.ToLower().Contains(input.Filter));
} }
public async Task<List<TagDefinitionDto>> GetTagDefinitionsAsync()
{
var definitions = await TagManager.GetTagDefinitionsAsync();
return definitions
.Select(s =>
new TagDefinitionDto(s.EntityType, s.DisplayName.Localize(StringLocalizerFactory)))
.ToList();
}
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs

@ -48,7 +48,7 @@ namespace Volo.CmsKit.Admin.Contents
[HttpGet] [HttpGet]
[Authorize(CmsKitAdminPermissions.Contents.Default)] [Authorize(CmsKitAdminPermissions.Contents.Default)]
public Task<PagedResultDto<ContentDto>> GetListAsync(ContentGetListInput input) public Task<PagedResultDto<ContentGetListDto>> GetListAsync(ContentGetListInput input)
{ {
return ContentAdminAppService.GetListAsync(input); return ContentAdminAppService.GetListAsync(input);
} }

6
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
@ -60,5 +61,10 @@ namespace Volo.CmsKit.Admin.Tags
{ {
return TagAdminAppService.UpdateAsync(id, input); return TagAdminAppService.UpdateAsync(id, input);
} }
public Task<List<TagDefinitionDto>> GetTagDefinitionsAsync()
{
return TagAdminAppService.GetTagDefinitionsAsync();
}
} }
} }

10
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs

@ -2,10 +2,14 @@
{ {
public static class CmsKitErrorCodes public static class CmsKitErrorCodes
{ {
public const string TagAlreadyExist = "CmsKit:0001"; public static class Tags
{
public const string TagAlreadyExist = "CmsKit:Tag:0001";
public const string EntityNotTaggable = "CmsKit:Tag:0002";
}
public const string ContentAlreadyExist = "CmsKit:0002"; public const string ContentAlreadyExist = "CmsKit:0002";
public static class Pages public static class Pages
{ {
public const string UrlAlreadyExist = "CmsKit:Page:0001"; public const string UrlAlreadyExist = "CmsKit:Page:0001";

1
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json

@ -2,6 +2,7 @@
"culture": "en", "culture": "en",
"texts": { "texts": {
"CmsKit:0002": "Content already exists!", "CmsKit:0002": "Content already exists!",
"CmsKit:0003": "The entity {0} is not taggable.",
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.", "CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
"Comments": "Comments", "Comments": "Comments",
"Delete": "Delete", "Delete": "Delete",

1
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json

@ -2,6 +2,7 @@
"culture": "tr", "culture": "tr",
"texts": { "texts": {
"CmsKit:0002": "İçerik zaten mevcut!", "CmsKit:0002": "İçerik zaten mevcut!",
"CmsKit:0003": "{0} ögesi etiketlenebilir değil.",
"CommentAuthorizationExceptionMessage": "Bu yorumları görebilmek için yetki gerekir.", "CommentAuthorizationExceptionMessage": "Bu yorumları görebilmek için yetki gerekir.",
"Comments": "Yorumlar", "Comments": "Yorumlar",
"Delete": "Sil", "Delete": "Sil",

22
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs

@ -1,7 +1,14 @@
using Volo.Abp.Domain; using Microsoft.Extensions.Options;
using Volo.Abp.Domain;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Users; using Volo.Abp.Users;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Localization;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Reactions; using Volo.CmsKit.Reactions;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit namespace Volo.CmsKit
{ {
@ -28,7 +35,18 @@ namespace Volo.CmsKit
options.Reactions.AddOrReplace(StandardReactions.HeartBroken); options.Reactions.AddOrReplace(StandardReactions.HeartBroken);
options.Reactions.AddOrReplace(StandardReactions.Rocket); options.Reactions.AddOrReplace(StandardReactions.Rocket);
options.Reactions.AddOrReplace(StandardReactions.Pray); options.Reactions.AddOrReplace(StandardReactions.Pray);
}); });
if (GlobalFeatureManager.Instance.IsEnabled<TagsFeature>())
{
// TODO: Configure TagEntityTypes here...
}
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<CmsKitResource>(name);
} }
} }
} }

8
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitOptions.cs

@ -1,16 +1,12 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using Volo.CmsKit.Reactions; using Volo.CmsKit.Reactions;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit namespace Volo.CmsKit
{ {
public class CmsKitOptions public class CmsKitOptions
{ {
[NotNull] [NotNull]
public ReactionDefinitionDictionary Reactions { get; } public ReactionDefinitionDictionary Reactions { get; } = new ReactionDefinitionDictionary();
public CmsKitOptions()
{
Reactions = new ReactionDefinitionDictionary();
}
} }
} }

32
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs

@ -0,0 +1,32 @@
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Localization;
namespace Volo.CmsKit.Domain.Volo.CmsKit
{
public abstract class PolicySpecifiedDefinition
{
protected PolicySpecifiedDefinition()
{
}
public PolicySpecifiedDefinition(
[CanBeNull] string createPolicy = null,
[CanBeNull] string updatePolicy = null,
[CanBeNull] string deletePolicy = null)
{
CreatePolicy = createPolicy;
DeletePolicy = deletePolicy;
UpdatePolicy = updatePolicy;
}
[CanBeNull]
public virtual string CreatePolicy { get; set; }
[CanBeNull]
public virtual string UpdatePolicy { get; set; }
[CanBeNull]
public virtual string DeletePolicy { get; set; }
}
}

11
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/CmsKitTagOptions.cs

@ -0,0 +1,11 @@
using JetBrains.Annotations;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit.Tags
{
public class CmsKitTagOptions
{
[NotNull]
public TagEntityTypeDefinitionDictionary EntityTypes { get; } = new TagEntityTypeDefinitionDictionary();
}
}

40
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs

@ -0,0 +1,40 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace Volo.CmsKit.Tags
{
public class DefaultTagDefinitionStore : ITagDefinitionStore, ITransientDependency
{
private readonly CmsKitTagOptions options;
public DefaultTagDefinitionStore(IOptions<CmsKitTagOptions> options)
{
this.options = options.Value;
}
public virtual Task<TagEntityTypeDefiniton> GetTagEntityTypeDefinitionsAsync([NotNull] string entityType)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
var result = options.EntityTypes.GetOrDefault(entityType) ?? throw new EntityNotTaggableException(entityType);
return Task.FromResult(result);
}
public virtual Task<List<TagEntityTypeDefiniton>> GetTagDefinitionsAsync()
{
return Task.FromResult(options.EntityTypes.Values.ToList());
}
public virtual Task<bool> IsDefinedAsync([NotNull] string entityType)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
return Task.FromResult(options.EntityTypes.ContainsKey(entityType));
}
}
}

26
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityNotTaggableException.cs

@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;
using System;
using Volo.Abp;
namespace Volo.CmsKit.Tags
{
[Serializable]
public class EntityNotTaggableException : BusinessException
{
public EntityNotTaggableException(
string code = null,
string message = null,
string details = null,
Exception innerException = null,
LogLevel logLevel = LogLevel.Warning)
: base(code, message, details, innerException, logLevel)
{
}
public EntityNotTaggableException(string entityType)
{
Code = CmsKitErrorCodes.Tags.EntityNotTaggable;
WithData(nameof(Tag.EntityType), entityType);
}
}
}

3
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTag.cs

@ -16,7 +16,7 @@ namespace Volo.CmsKit.Tags
{ {
} }
public EntityTag(Guid tagId, string entityId, Guid? tenantId = null) internal EntityTag(Guid tagId, string entityId, Guid? tenantId = null)
{ {
TagId = tagId; TagId = tagId;
EntityId = entityId; EntityId = entityId;
@ -27,6 +27,5 @@ namespace Volo.CmsKit.Tags
{ {
return new object[] { TagId, EntityId }; return new object[] { TagId, EntityId };
} }
} }
} }

52
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs

@ -0,0 +1,52 @@
using JetBrains.Annotations;
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit.Tags
{
public class EntityTagManager : DomainService, IEntityTagManager
{
protected readonly IEntityTagRepository _entityTagRepository;
protected readonly ITagDefinitionStore _tagDefinitionStore;
public EntityTagManager(
IEntityTagRepository entityTagRepository,
ITagDefinitionStore tagDefinitionStore)
{
_entityTagRepository = entityTagRepository;
_tagDefinitionStore = tagDefinitionStore;
}
public async Task<EntityTag> AddTagToEntityAsync(
[NotNull] Guid tagId,
[NotNull] string entityType,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId = null,
CancellationToken cancellationToken = default)
{
if (!await _tagDefinitionStore.IsDefinedAsync(entityType))
{
throw new EntityNotTaggableException(entityType);
}
var entityTag = new EntityTag(tagId, entityId, tenantId);
return await _entityTagRepository.InsertAsync(entityTag, cancellationToken: cancellationToken);
}
public async Task RemoveTagFromEntityAsync(
[NotNull] Guid tagId,
[NotNull] string entityType,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId = null,
CancellationToken cancellationToken = default)
{
var entityTag = await _entityTagRepository.FindAsync(tagId, entityId, tenantId, cancellationToken);
await _entityTagRepository.DeleteAsync(entityTag);
}
}
}

24
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagManager.cs

@ -0,0 +1,24 @@
using JetBrains.Annotations;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Volo.CmsKit.Tags
{
public interface IEntityTagManager
{
Task<EntityTag> AddTagToEntityAsync(
[NotNull] Guid tagId,
[NotNull] string entityType,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId = null,
CancellationToken cancellationToken = default);
Task RemoveTagFromEntityAsync(
[NotNull] Guid tagId,
[NotNull] string entityType,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId = null,
CancellationToken cancellationToken = default);
}
}

12
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs

@ -1,9 +1,17 @@
using Volo.Abp.Domain.Repositories; using JetBrains.Annotations;
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Volo.CmsKit.Tags namespace Volo.CmsKit.Tags
{ {
public interface IEntityTagRepository : IBasicRepository<EntityTag> public interface IEntityTagRepository : IBasicRepository<EntityTag>
{ {
Task<EntityTag> FindAsync(
[NotNull] Guid tagId,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId,
CancellationToken cancellationToken = default);
} }
} }

15
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs

@ -0,0 +1,15 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Volo.CmsKit.Tags
{
public interface ITagDefinitionStore
{
Task<List<TagEntityTypeDefiniton>> GetTagDefinitionsAsync();
Task<TagEntityTypeDefiniton> GetTagEntityTypeDefinitionsAsync([NotNull] string entityType);
Task<bool> IsDefinedAsync([NotNull] string entityType);
}
}

3
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagManager.cs

@ -1,5 +1,6 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Services; using Volo.Abp.Domain.Services;
@ -26,5 +27,7 @@ namespace Volo.CmsKit.Tags
[NotNull] string name, [NotNull] string name,
Guid? tenantId = null, Guid? tenantId = null,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
Task<List<TagEntityTypeDefiniton>> GetTagDefinitionsAsync(CancellationToken cancellationToken = default);
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagAlreadyExistException.cs

@ -9,7 +9,7 @@ namespace Volo.CmsKit.Tags
{ {
public TagAlreadyExistException([NotNull] string entityType, [NotNull] string name) public TagAlreadyExistException([NotNull] string entityType, [NotNull] string name)
{ {
Code = CmsKitErrorCodes.TagAlreadyExist; Code = CmsKitErrorCodes.Tags.TagAlreadyExist;
WithData(nameof(Tag.EntityType), entityType); WithData(nameof(Tag.EntityType), entityType);
WithData(nameof(Tag.Name), name); WithData(nameof(Tag.Name), name);
} }

20
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefinitionDictionary.cs

@ -0,0 +1,20 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using Volo.Abp.Localization;
namespace Volo.CmsKit.Tags
{
public class TagEntityTypeDefinitionDictionary : Dictionary<string, TagEntityTypeDefiniton>
{
public void AddOrReplace(
[NotNull] string entityType,
[CanBeNull] ILocalizableString displayName = null,
[CanBeNull] string createPolicy = null,
[CanBeNull] string updatePolicy = null,
[CanBeNull] string deletePolicy = null
)
{
this[entityType] = new TagEntityTypeDefiniton(entityType, displayName, createPolicy, updatePolicy, deletePolicy);
}
}
}

31
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton1.cs

@ -0,0 +1,31 @@
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Localization;
using Volo.CmsKit.Domain.Volo.CmsKit;
namespace Volo.CmsKit.Tags
{
public class TagEntityTypeDefiniton : PolicySpecifiedDefinition
{
public string EntityType { get; }
[CanBeNull]
public virtual ILocalizableString DisplayName { get; }
public TagEntityTypeDefiniton()
{
}
public TagEntityTypeDefiniton(
[NotNull] string entityType,
[CanBeNull] ILocalizableString displayName = null,
[CanBeNull] string createPolicy = null,
[CanBeNull] string updatePolicy = null,
[CanBeNull] string deletePolicy = null) : base(createPolicy, updatePolicy, deletePolicy)
{
EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
DisplayName = displayName;
}
}
}

19
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagManager.cs

@ -1,5 +1,8 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
@ -10,10 +13,14 @@ namespace Volo.CmsKit.Tags
public class TagManager : DomainService, ITagManager public class TagManager : DomainService, ITagManager
{ {
private readonly ITagRepository _tagRepository; private readonly ITagRepository _tagRepository;
private readonly ITagDefinitionStore _tagDefinitionStore;
public TagManager(ITagRepository tagRepository) public TagManager(
ITagRepository tagRepository,
ITagDefinitionStore tagDefinitionStore)
{ {
_tagRepository = tagRepository; _tagRepository = tagRepository;
_tagDefinitionStore = tagDefinitionStore;
} }
public async Task<Tag> GetOrAddAsync( public async Task<Tag> GetOrAddAsync(
@ -44,6 +51,11 @@ namespace Volo.CmsKit.Tags
throw new TagAlreadyExistException(entityType, name); throw new TagAlreadyExistException(entityType, name);
} }
if (!await _tagDefinitionStore.IsDefinedAsync(entityType))
{
throw new EntityNotTaggableException(entityType);
}
return await _tagRepository.InsertAsync( return await _tagRepository.InsertAsync(
new Tag( new Tag(
id, id,
@ -70,5 +82,10 @@ namespace Volo.CmsKit.Tags
return await _tagRepository.UpdateAsync(entity, cancellationToken: cancellationToken); return await _tagRepository.UpdateAsync(entity, cancellationToken: cancellationToken);
} }
public Task<List<TagEntityTypeDefiniton>> GetTagDefinitionsAsync(CancellationToken cancellationToken = default)
{
return _tagDefinitionStore.GetTagDefinitionsAsync();
}
} }
} }

19
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs

@ -1,4 +1,8 @@
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using JetBrains.Annotations;
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore;
@ -9,5 +13,18 @@ namespace Volo.CmsKit.Tags
public EfCoreEntityTagRepository(IDbContextProvider<ICmsKitDbContext> dbContextProvider) : base(dbContextProvider) public EfCoreEntityTagRepository(IDbContextProvider<ICmsKitDbContext> dbContextProvider) : base(dbContextProvider)
{ {
} }
public Task<EntityTag> FindAsync(
[NotNull] Guid tagId,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId,
CancellationToken cancellationToken = default)
{
return base.FindAsync(x =>
x.TagId == tagId &&
x.EntityId == entityId &&
x.TenantId == tenantId,
cancellationToken: cancellationToken);
}
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs

@ -54,7 +54,7 @@ namespace Volo.CmsKit.MongoDB.Contents
public async Task<bool> ExistsAsync([NotNull] string entityType, [NotNull] string entityId, Guid? tenantId = null, CancellationToken cancellationToken = default) public async Task<bool> ExistsAsync([NotNull] string entityType, [NotNull] string entityId, Guid? tenantId = null, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()).AnyAsync(x => return await (await GetMongoQueryableAsync(cancellationToken)).AnyAsync(x =>
x.EntityType == entityType && x.EntityType == entityType &&
x.EntityId == entityId && x.EntityId == entityId &&
x.TenantId == tenantId, x.TenantId == tenantId,

2
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs

@ -63,7 +63,7 @@ namespace Volo.CmsKit.MongoDB.Pages
public virtual async Task<bool> ExistsAsync(string url, CancellationToken cancellationToken = default) public virtual async Task<bool> ExistsAsync(string url, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(GetCancellationToken(cancellationToken))).AnyAsync(x => x.Url == url, GetCancellationToken(cancellationToken)); return await (await GetMongoQueryableAsync(cancellationToken)).AnyAsync(x => x.Url == url, GetCancellationToken(cancellationToken));
} }
} }
} }

19
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs

@ -1,4 +1,8 @@
using Volo.Abp.Domain.Repositories.MongoDB; using JetBrains.Annotations;
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB; using Volo.Abp.MongoDB;
using Volo.CmsKit.Tags; using Volo.CmsKit.Tags;
@ -9,5 +13,18 @@ namespace Volo.CmsKit.MongoDB.Tags
public MongoEntityTagRepository(IMongoDbContextProvider<ICmsKitMongoDbContext> dbContextProvider) : base(dbContextProvider) public MongoEntityTagRepository(IMongoDbContextProvider<ICmsKitMongoDbContext> dbContextProvider) : base(dbContextProvider)
{ {
} }
public Task<EntityTag> FindAsync(
[NotNull] Guid tagId,
[NotNull] string entityId,
[CanBeNull] Guid? tenantId,
CancellationToken cancellationToken = default)
{
return base.FindAsync(x =>
x.TagId == tagId &&
x.EntityId == entityId &&
x.TenantId == tenantId,
cancellationToken: cancellationToken);
}
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/IPageAppService.cs

@ -5,6 +5,6 @@ namespace Volo.CmsKit.Public.Pages
{ {
public interface IPageAppService public interface IPageAppService
{ {
Task<PageDto> GetByUrlAsync([NotNull] string url); Task<PageDto> FindByUrlAsync([NotNull] string url);
} }
} }

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

@ -12,9 +12,14 @@ namespace Volo.CmsKit.Public.Pages
PageRepository = pageRepository; PageRepository = pageRepository;
} }
public virtual async Task<PageDto> GetByUrlAsync(string url) public virtual async Task<PageDto> FindByUrlAsync(string url)
{ {
var page = await PageRepository.GetByUrlAsync(url); var page = await PageRepository.FindByUrlAsync(url);
if (page == null)
{
return null;
}
return ObjectMapper.Map<Page, PageDto>(page); return ObjectMapper.Map<Page, PageDto>(page);
} }

6
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs

@ -7,7 +7,7 @@ namespace Volo.CmsKit.Public.Pages
[RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)]
[Area("cms-kit")] [Area("cms-kit")]
[Route("api/cms-kit-public/comments")] [Route("api/cms-kit-public/comments")]
public class PagesPublicController public class PagesPublicController : IPageAppService
{ {
protected readonly IPageAppService PageAppService; protected readonly IPageAppService PageAppService;
@ -18,9 +18,9 @@ namespace Volo.CmsKit.Public.Pages
[HttpGet] [HttpGet]
[Route("url/{url}")] [Route("url/{url}")]
public Task<PageDto> GetByUrlAsync(string url) public Task<PageDto> FindByUrlAsync(string url)
{ {
return PageAppService.GetByUrlAsync(url); return PageAppService.FindByUrlAsync(url);
} }
} }
} }

5
modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc.RazorPages; using System.Linq;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
@ -56,7 +57,7 @@ namespace Volo.CmsKit.Public.Web
Configure<RazorPagesOptions>(options => Configure<RazorPagesOptions>(options =>
{ {
//... options.Conventions.AddPageRoute("/CmsKit/Pages/Index", "/{*pageUrl}");
}); });
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml

@ -1,4 +1,4 @@
@page "{pageUrl}" @page "{*pageUrl}"
@using Microsoft.AspNetCore.Mvc.Localization @using Microsoft.AspNetCore.Mvc.Localization
@using Volo.CmsKit.Localization @using Volo.CmsKit.Localization
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages

11
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs

@ -19,9 +19,16 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Pages
PageAppService = pageAppService; PageAppService = pageAppService;
} }
public async Task OnGetAsync() public async Task<IActionResult> OnGetAsync()
{ {
Page = await PageAppService.GetByUrlAsync(PageUrl); Page = await PageAppService.FindByUrlAsync(PageUrl);
if (Page == null)
{
return NotFound();
}
return Page();
} }
} }
} }

32
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/ContentViewComponent.cs

@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Domain.Entities;
using Volo.CmsKit.Public.Contents; using Volo.CmsKit.Public.Contents;
using Volo.CmsKit.Web.Contents; using Volo.CmsKit.Web.Contents;
@ -25,18 +26,26 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents
string entityType, string entityType,
string entityId) string entityId)
{ {
var content = await contentAppService.GetAsync(new GetContentInput var content = string.Empty;
try
{ {
EntityId = entityId, var contentDto = await contentAppService.GetAsync(new GetContentInput
EntityType = entityType {
}); EntityId = entityId,
EntityType = entityType
});
content = contentDto.Value;
}
catch (EntityNotFoundException e)
{
// ContentDto can be null, we will render empty content.
}
var viewModel = new ContentViewModel var viewModel = new ContentViewModel
{ {
EntityId = entityId, Value = await contentRenderer.RenderAsync(content)
EntityType = entityType,
ContentId = content.Id,
Rendered = await contentRenderer.RenderAsync(content.Value)
}; };
return View("~/Pages/CmsKit/Shared/Components/Contents/Default.cshtml", viewModel); return View("~/Pages/CmsKit/Shared/Components/Contents/Default.cshtml", viewModel);
@ -44,12 +53,7 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents
public class ContentViewModel public class ContentViewModel
{ {
public Guid ContentId { get; set; } public string Value { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public string Rendered { get; set; }
} }
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/Default.cshtml

@ -1,3 +1,3 @@
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents.ContentViewComponent.ContentViewModel @model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents.ContentViewComponent.ContentViewModel
@Html.Raw(Model.Rendered) @Html.Raw(Model.Value)

12
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/Default.cshtml

@ -1,16 +1,16 @@
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@using Microsoft.AspNetCore.Mvc.RazorPages @using Microsoft.AspNetCore.Mvc.RazorPages
@using Volo.Abp.AspNetCore.Mvc.UI.Layout
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages.PageViewModel @model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages.PageViewModel
@inject IPageLayout PageLayout
@{
PageLayout.Content.Title = Model.Title;
}
<abp-card> <abp-card>
<abp-card-header>
<h3>
@Model.Title
</h3>
</abp-card-header>
<abp-card-body> <abp-card-body>
@await Component.InvokeAsync(typeof(ContentViewComponent), @await Component.InvokeAsync(typeof(ContentViewComponent),
new new

3
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs

@ -38,6 +38,7 @@ namespace Volo.CmsKit.Contents
result.ShouldNotBeNull(); result.ShouldNotBeNull();
result.Items.ShouldNotBeEmpty(); result.Items.ShouldNotBeEmpty();
result.Items.Count.ShouldBe(4); result.Items.Count.ShouldBe(4);
result.Items.All(x => x.ShouldBeOfType<ContentGetListDto>() != null);
} }
[Fact] [Fact]
@ -46,6 +47,8 @@ namespace Volo.CmsKit.Contents
var result = await _service.GetAsync(_data.Content_1_Id); var result = await _service.GetAsync(_data.Content_1_Id);
result.ShouldNotBeNull(); result.ShouldNotBeNull();
result.ShouldBeOfType<Admin.Contents.ContentDto>();
result.ShouldNotBeNull(result.Value);
} }
[Fact] [Fact]

11
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PagePublicAppService_Tests.cs

@ -18,15 +18,20 @@ namespace Volo.CmsKit.Pages
} }
[Fact] [Fact]
public async Task ShouldGetByUrlAsync() public async Task ShouldFindByUrlAsync()
{ {
await Should.NotThrowAsync(async () => await _pageAppService.GetByUrlAsync(_data.Page_1_Url)); var page = await _pageAppService.FindByUrlAsync(_data.Page_1_Url);
page.ShouldNotBeNull();
page.Title.ShouldBe(_data.Page_1_Title);
} }
[Fact] [Fact]
public async Task ShouldNotGetByUrlAsync() public async Task ShouldNotGetByUrlAsync()
{ {
await Should.ThrowAsync<Exception>(async () => await _pageAppService.GetByUrlAsync("not-exist-url")); var page = await _pageAppService.FindByUrlAsync("not-exist-url");
page.ShouldBeNull();
} }
} }
} }

4
modules/cms-kit/test/Volo.CmsKit.Application.Tests/Tags/TagAdminAppService_Tests.cs

@ -32,8 +32,8 @@ namespace Volo.CmsKit.Tags
{ {
var list = await _tagAdminAppService.CreateAsync(new TagCreateDto var list = await _tagAdminAppService.CreateAsync(new TagCreateDto
{ {
EntityType = "any_new_type", EntityType = _cmsKitTestData.EntityType1,
Name = "1", Name = "My First Tag",
}); });
list.Id.ShouldNotBe(Guid.Empty); list.Id.ShouldNotBe(Guid.Empty);

1
modules/cms-kit/test/Volo.CmsKit.Domain.Tests/CmsKitDomainTestModule.cs

@ -12,6 +12,5 @@ namespace Volo.CmsKit
)] )]
public class CmsKitDomainTestModule : AbpModule public class CmsKitDomainTestModule : AbpModule
{ {
} }
} }

60
modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/EntityTagManager_Tests.cs

@ -0,0 +1,60 @@
using Shouldly;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Guids;
using Xunit;
namespace Volo.CmsKit.Tags
{
public class EntityTagManager_Tests : CmsKitDomainTestBase
{
private readonly CmsKitTestData _cmsKitTestData;
private readonly IEntityTagManager _entityTagManager;
private readonly ITagRepository _tagRepository;
private readonly IGuidGenerator _guidGenerator;
public EntityTagManager_Tests()
{
_cmsKitTestData = GetRequiredService<CmsKitTestData>();
_entityTagManager = GetRequiredService<IEntityTagManager>();
_tagRepository = GetRequiredService<ITagRepository>();
_guidGenerator = GetRequiredService<IGuidGenerator>();
}
[Fact]
public async Task AddTagToEntityAsync_ShouldAdd_WhenEverythingCorrect()
{
var tag = await _tagRepository.InsertAsync(new Tag(_guidGenerator.Create(), _cmsKitTestData.EntityType1, "My Test Tag #1"));
var entityTag = await _entityTagManager.AddTagToEntityAsync(tag.Id, _cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1);
entityTag.ShouldNotBeNull();
}
[Fact]
public async Task AddTagToEntity_ShouldThrowNotTaggable_WithNotConfiguredEntityType()
{
var entityType = "Not.Configured.EntityType";
var exception = Should.Throw<EntityNotTaggableException>(async () =>
await _entityTagManager.AddTagToEntityAsync(_cmsKitTestData.TagId_1, entityType, _cmsKitTestData.EntityId1)
);
exception.ShouldNotBeNull();
exception.Data[nameof(Tag.EntityType)].ShouldBe(entityType);
}
[Fact]
public async Task RemoveTagFromEntityAsync_ShouldRemove_WhenEverythingCorrect()
{
var tagToDelete = (await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1))
.First();
await _entityTagManager.RemoveTagFromEntityAsync(tagToDelete.Id, tagToDelete.EntityType, _cmsKitTestData.EntityId1);
var tags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1);
tags.ShouldNotContain(x => x.Id == tagToDelete.Id);
}
}
}

30
modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagManager_Tests.cs

@ -22,7 +22,7 @@ namespace Volo.CmsKit.Tags
[Fact] [Fact]
public async Task ShouldAddWhenGettingAsync() public async Task ShouldAddWhenGettingAsync()
{ {
var newTagEntityType = "testEntity"; var newTagEntityType = _cmsKitTestData.EntityType1;
var newTagName = "test_tag_2123"; var newTagName = "test_tag_2123";
var doesExist = await _tagRepository.AnyAsync(newTagEntityType, newTagName); var doesExist = await _tagRepository.AnyAsync(newTagEntityType, newTagName);
@ -53,16 +53,28 @@ namespace Volo.CmsKit.Tags
} }
[Fact] [Fact]
public async Task ShouldInsert() public async Task ShouldInsertAsync()
{ {
var tag = await _tagManager.InsertAsync(Guid.NewGuid(), "test", "test"); var tagName = "Freshly Created New Tag";
var tag = await _tagManager.InsertAsync(Guid.NewGuid(), _cmsKitTestData.EntityType1, tagName);
tag.ShouldNotBeNull(); tag.ShouldNotBeNull();
var doesExist = await _tagRepository.AnyAsync("test", "test"); var doesExist = await _tagRepository.AnyAsync(_cmsKitTestData.EntityType1, tagName);
doesExist.ShouldBeTrue(); doesExist.ShouldBeTrue();
} }
[Fact]
public async Task ShouldntInsertWithUnconfiguredEntityTypeAsync()
{
var notConfiguredEntityType = "My.Namespace.SomeEntity";
var exception = await Should.ThrowAsync<EntityNotTaggableException>(async () =>
await _tagManager.InsertAsync(Guid.NewGuid(), notConfiguredEntityType, "test"));
exception.ShouldNotBeNull();
exception.Data[nameof(Tag.EntityType)].ShouldBe(notConfiguredEntityType);
}
[Fact] [Fact]
public async Task ShouldNotInsert() public async Task ShouldNotInsert()
@ -100,5 +112,15 @@ namespace Volo.CmsKit.Tags
Should.Throw<Exception>(async () => await _tagManager.UpdateAsync(tag.Id, newName)); Should.Throw<Exception>(async () => await _tagManager.UpdateAsync(tag.Id, newName));
} }
[Fact]
public async Task ShouldGetTagDefinitionsProperly_WithoutParameter()
{
var definitions = await _tagManager.GetTagDefinitionsAsync();
definitions.ShouldNotBeNull();
definitions.Count.ShouldBeGreaterThan(1);
definitions.ShouldContain(x => x.EntityType == _cmsKitTestData.TagDefinition_1_EntityType);
}
} }
} }

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

@ -1,4 +1,5 @@
using System; using Microsoft.Extensions.Options;
using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Data; using Volo.Abp.Data;
@ -26,9 +27,12 @@ namespace Volo.CmsKit
private readonly IRatingRepository _ratingRepository; private readonly IRatingRepository _ratingRepository;
private readonly ICurrentTenant _currentTenant; private readonly ICurrentTenant _currentTenant;
private readonly IContentRepository _contentRepository; private readonly IContentRepository _contentRepository;
private readonly IEntityTagRepository _entityTagRepository; private readonly IEntityTagManager _entityTagManager;
private readonly ITagManager _tagManager; private readonly ITagManager _tagManager;
private readonly IPageRepository _pageRepository; private readonly IPageRepository _pageRepository;
private readonly IOptions<CmsKitOptions> _options;
private readonly IOptions<CmsKitTagOptions> _tagOptions;
public CmsKitDataSeedContributor( public CmsKitDataSeedContributor(
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
ICmsUserRepository cmsUserRepository, ICmsUserRepository cmsUserRepository,
@ -36,11 +40,13 @@ namespace Volo.CmsKit
ICommentRepository commentRepository, ICommentRepository commentRepository,
ReactionManager reactionManager, ReactionManager reactionManager,
IRatingRepository ratingRepository, IRatingRepository ratingRepository,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IContentRepository contentRepository, IContentRepository contentRepository,
ITagManager tagManager, ITagManager tagManager,
IEntityTagRepository entityTagRepository, IEntityTagManager entityTagManager,
IPageRepository pageRepository) IPageRepository pageRepository,
IOptions<CmsKitOptions> options,
IOptions<CmsKitTagOptions> tagOptions)
{ {
_guidGenerator = guidGenerator; _guidGenerator = guidGenerator;
_cmsUserRepository = cmsUserRepository; _cmsUserRepository = cmsUserRepository;
@ -51,14 +57,18 @@ namespace Volo.CmsKit
_currentTenant = currentTenant; _currentTenant = currentTenant;
_contentRepository = contentRepository; _contentRepository = contentRepository;
_tagManager = tagManager; _tagManager = tagManager;
_entityTagRepository = entityTagRepository; _entityTagManager = entityTagManager;
_pageRepository = pageRepository; _pageRepository = pageRepository;
_options = options;
_tagOptions = tagOptions;
} }
public async Task SeedAsync(DataSeedContext context) public async Task SeedAsync(DataSeedContext context)
{ {
using (_currentTenant.Change(context?.TenantId)) using (_currentTenant.Change(context?.TenantId))
{ {
await ConfigureCmsKitOptionsAsync();
await SeedUsersAsync(); await SeedUsersAsync();
await SeedCommentsAsync(); await SeedCommentsAsync();
@ -75,6 +85,17 @@ namespace Volo.CmsKit
} }
} }
private Task ConfigureCmsKitOptionsAsync()
{
_tagOptions.Value.EntityTypes.AddOrReplace(_cmsKitTestData.EntityType1);
_tagOptions.Value.EntityTypes.AddOrReplace(_cmsKitTestData.EntityType2);
_tagOptions.Value.EntityTypes.AddOrReplace(_cmsKitTestData.Content_1_EntityType);
_tagOptions.Value.EntityTypes.AddOrReplace(_cmsKitTestData.Content_2_EntityType);
_tagOptions.Value.EntityTypes.AddOrReplace(_cmsKitTestData.TagDefinition_1_EntityType);
return Task.CompletedTask;
}
private async Task SeedUsersAsync() private async Task SeedUsersAsync()
{ {
await _cmsUserRepository.InsertAsync(new CmsUser(new UserData(_cmsKitTestData.User1Id, "user1", await _cmsUserRepository.InsertAsync(new CmsUser(new UserData(_cmsKitTestData.User1Id, "user1",
@ -208,14 +229,14 @@ namespace Volo.CmsKit
_cmsKitTestData.Content_1_EntityId, _cmsKitTestData.Content_1_EntityId,
_cmsKitTestData.Content_1 _cmsKitTestData.Content_1
); );
var content2 = new Content( var content2 = new Content(
_cmsKitTestData.Content_2_Id, _cmsKitTestData.Content_2_Id,
_cmsKitTestData.Content_2_EntityType, _cmsKitTestData.Content_2_EntityType,
_cmsKitTestData.Content_2_EntityId, _cmsKitTestData.Content_2_EntityId,
_cmsKitTestData.Content_2 _cmsKitTestData.Content_2
); );
var content3 = new Content( var content3 = new Content(
Guid.NewGuid(), Guid.NewGuid(),
"deleted_entity_type", "deleted_entity_type",
@ -233,18 +254,26 @@ namespace Volo.CmsKit
private async Task SeedTagsAsync() private async Task SeedTagsAsync()
{ {
var created1 = await _tagManager.InsertAsync(_cmsKitTestData.TagId_1, _cmsKitTestData.EntityType1, _cmsKitTestData.TagName_1);
await _entityTagManager.AddTagToEntityAsync(created1.Id, created1.EntityType, _cmsKitTestData.EntityId1);
var created2 = await _tagManager.InsertAsync(_cmsKitTestData.TagId_2, _cmsKitTestData.EntityType2, _cmsKitTestData.TagName_2);
await _entityTagManager.AddTagToEntityAsync(created2.Id, created2.EntityType, _cmsKitTestData.EntityId2);
foreach (var tag in _cmsKitTestData.Content_1_Tags) foreach (var tag in _cmsKitTestData.Content_1_Tags)
{ {
var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_1_EntityType, tag); var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_1_EntityType, tag);
await _entityTagRepository.InsertAsync(new EntityTag(tagEntity.Id, _cmsKitTestData.Content_1_EntityId)); await _entityTagManager.AddTagToEntityAsync(tagEntity.Id, _cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId);
} }
foreach (var tag in _cmsKitTestData.Content_2_Tags) foreach (var tag in _cmsKitTestData.Content_2_Tags)
{ {
var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_2_EntityType, tag); var tagEntity = await _tagManager.InsertAsync(_guidGenerator.Create(), _cmsKitTestData.Content_2_EntityType, tag);
await _entityTagRepository.InsertAsync(new EntityTag(tagEntity.Id, _cmsKitTestData.Content_2_EntityId)); await _entityTagManager.AddTagToEntityAsync(tagEntity.Id, _cmsKitTestData.Content_2_EntityType, _cmsKitTestData.Content_2_EntityId);
} }
} }
@ -252,10 +281,10 @@ namespace Volo.CmsKit
{ {
var page1 = new Page(_cmsKitTestData.Page_1_Id, _cmsKitTestData.Page_1_Title, _cmsKitTestData.Page_1_Url, _cmsKitTestData.Page_1_Description); var page1 = new Page(_cmsKitTestData.Page_1_Id, _cmsKitTestData.Page_1_Title, _cmsKitTestData.Page_1_Url, _cmsKitTestData.Page_1_Description);
var page1Content = new Content(_guidGenerator.Create(), nameof(Page), page1.Id.ToString(), _cmsKitTestData.Page_1_Content); var page1Content = new Content(_guidGenerator.Create(), nameof(Page), page1.Id.ToString(), _cmsKitTestData.Page_1_Content);
await _pageRepository.InsertAsync(page1); await _pageRepository.InsertAsync(page1);
await _contentRepository.InsertAsync(page1Content); await _contentRepository.InsertAsync(page1Content);
var page2 = new Page(_cmsKitTestData.Page_2_Id, _cmsKitTestData.Page_2_Title, _cmsKitTestData.Page_2_Url, _cmsKitTestData.Page_2_Description); var page2 = new Page(_cmsKitTestData.Page_2_Id, _cmsKitTestData.Page_2_Title, _cmsKitTestData.Page_2_Url, _cmsKitTestData.Page_2_Description);
var page2Content = new Content(_guidGenerator.Create(), nameof(Page), page2.Id.ToString(), _cmsKitTestData.Page_2_Content); var page2Content = new Content(_guidGenerator.Create(), nameof(Page), page2.Id.ToString(), _cmsKitTestData.Page_2_Content);

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

@ -12,6 +12,7 @@ namespace Volo.CmsKit
public Guid CommentWithChildId { get; } = Guid.NewGuid(); public Guid CommentWithChildId { get; } = Guid.NewGuid();
public string EntityType1 { get; } = "EntityName1"; public string EntityType1 { get; } = "EntityName1";
public string EntityType2 { get; } = "EntityName2"; public string EntityType2 { get; } = "EntityName2";
@ -59,5 +60,15 @@ namespace Volo.CmsKit
public Guid Page_2_Id { get; } = Guid.NewGuid(); public Guid Page_2_Id { get; } = Guid.NewGuid();
public string Page_2_Content => Content_2; public string Page_2_Content => Content_2;
public string TagDefinition_1_EntityType => "My.Namespace.CustomType";
public Guid TagId_1 { get; } = Guid.NewGuid();
public string TagName_1 => "Awesome";
public Guid TagId_2 { get; } = Guid.NewGuid();
public string TagName_2 => "News";
} }
} }

9
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -7,10 +8,10 @@ namespace Volo.Docs.Projects
{ {
public interface IProjectRepository : IBasicRepository<Project, Guid> public interface IProjectRepository : IBasicRepository<Project, Guid>
{ {
Task<List<Project>> GetListAsync(string sorting, int maxResultCount, int skipCount); Task<List<Project>> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default);
Task<Project> GetByShortNameAsync(string shortName); Task<Project> GetByShortNameAsync(string shortName, CancellationToken cancellationToken = default);
Task<bool> ShortNameExistsAsync(string shortName); Task<bool> ShortNameExistsAsync(string shortName, CancellationToken cancellationToken = default);
} }
} }

13
modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
@ -18,20 +19,20 @@ namespace Volo.Docs.Projects
{ {
} }
public async Task<List<Project>> GetListAsync(string sorting, int maxResultCount, int skipCount) public async Task<List<Project>> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default)
{ {
var projects = await (await GetDbSetAsync()).OrderBy(sorting ?? "Id desc") var projects = await (await GetDbSetAsync()).OrderBy(sorting ?? "Id desc")
.PageBy(skipCount, maxResultCount) .PageBy(skipCount, maxResultCount)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
return projects; return projects;
} }
public async Task<Project> GetByShortNameAsync(string shortName) public async Task<Project> GetByShortNameAsync(string shortName, CancellationToken cancellationToken = default)
{ {
var normalizeShortName = NormalizeShortName(shortName); var normalizeShortName = NormalizeShortName(shortName);
var project = await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.ShortName == normalizeShortName); var project = await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.ShortName == normalizeShortName, GetCancellationToken(cancellationToken));
if (project == null) if (project == null)
{ {
@ -41,11 +42,11 @@ namespace Volo.Docs.Projects
return project; return project;
} }
public async Task<bool> ShortNameExistsAsync(string shortName) public async Task<bool> ShortNameExistsAsync(string shortName, CancellationToken cancellationToken = default)
{ {
var normalizeShortName = NormalizeShortName(shortName); var normalizeShortName = NormalizeShortName(shortName);
return await (await GetDbSetAsync()).AnyAsync(x => x.ShortName == normalizeShortName); return await (await GetDbSetAsync()).AnyAsync(x => x.ShortName == normalizeShortName, GetCancellationToken(cancellationToken));
} }
private string NormalizeShortName(string shortName) private string NormalizeShortName(string shortName)

15
modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs

@ -9,6 +9,7 @@ using Volo.Abp.MongoDB;
using Volo.Docs.MongoDB; using Volo.Docs.MongoDB;
using System.Linq; using System.Linq;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
using System.Threading;
namespace Volo.Docs.Projects namespace Volo.Docs.Projects
{ {
@ -19,20 +20,20 @@ namespace Volo.Docs.Projects
{ {
} }
public async Task<List<Project>> GetListAsync(string sorting, int maxResultCount, int skipCount) public async Task<List<Project>> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default)
{ {
var projects = await (await GetMongoQueryableAsync()).OrderBy(sorting ?? "Id desc").As<IMongoQueryable<Project>>() var projects = await (await GetMongoQueryableAsync(cancellationToken)).OrderBy(sorting ?? "Id desc").As<IMongoQueryable<Project>>()
.PageBy<Project, IMongoQueryable<Project>>(skipCount, maxResultCount) .PageBy<Project, IMongoQueryable<Project>>(skipCount, maxResultCount)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
return projects; return projects;
} }
public async Task<Project> GetByShortNameAsync(string shortName) public async Task<Project> GetByShortNameAsync(string shortName, CancellationToken cancellationToken = default)
{ {
var normalizeShortName = NormalizeShortName(shortName); var normalizeShortName = NormalizeShortName(shortName);
var project = await (await GetMongoQueryableAsync()).FirstOrDefaultAsync(p => p.ShortName == normalizeShortName); var project = await (await GetMongoQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.ShortName == normalizeShortName, GetCancellationToken(cancellationToken));
if (project == null) if (project == null)
{ {
@ -42,11 +43,11 @@ namespace Volo.Docs.Projects
return project; return project;
} }
public async Task<bool> ShortNameExistsAsync(string shortName) public async Task<bool> ShortNameExistsAsync(string shortName, CancellationToken cancellationToken = default)
{ {
var normalizeShortName = NormalizeShortName(shortName); var normalizeShortName = NormalizeShortName(shortName);
return await (await GetMongoQueryableAsync()).AnyAsync(x => x.ShortName == normalizeShortName); return await (await GetMongoQueryableAsync(cancellationToken)).AnyAsync(x => x.ShortName == normalizeShortName, GetCancellationToken(cancellationToken));
} }
private string NormalizeShortName(string shortName) private string NormalizeShortName(string shortName)

18
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -7,10 +8,21 @@ namespace Volo.Abp.FeatureManagement
{ {
public interface IFeatureValueRepository : IBasicRepository<FeatureValue, Guid> public interface IFeatureValueRepository : IBasicRepository<FeatureValue, Guid>
{ {
Task<FeatureValue> FindAsync(string name, string providerName, string providerKey); Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<FeatureValue>> FindAllAsync(string name, string providerName, string providerKey); Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<FeatureValue>> GetListAsync(string providerName, string providerKey); Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
} }
} }

26
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
@ -15,29 +16,38 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
{ {
} }
public virtual async Task<FeatureValue> FindAsync(string name, string providerName, string providerKey) public virtual async Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.OrderBy(x => x.Id) .OrderBy(x => x.Id)
.FirstOrDefaultAsync( .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, GetCancellationToken(cancellationToken));
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey
);
} }
public async Task<List<FeatureValue>> FindAllAsync(string name, string providerName, string providerKey) public async Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.Where( .Where(
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(); ).ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<FeatureValue>> GetListAsync(string providerName, string providerKey) public virtual async Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.Where( .Where(
s => s.ProviderName == providerName && s.ProviderKey == providerKey s => s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(); ).ToListAsync(GetCancellationToken(cancellationToken));
} }
} }
} }

30
modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
@ -16,24 +17,35 @@ namespace Volo.Abp.FeatureManagement.MongoDB
} }
public virtual async Task<FeatureValue> FindAsync(string name, string providerName, string providerKey) public virtual async Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.OrderBy(x => x.Id) .OrderBy(x => x.Id)
.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, GetCancellationToken(cancellationToken));
} }
public async Task<List<FeatureValue>> FindAllAsync(string name, string providerName, string providerKey) public async Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); .Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<FeatureValue>> GetListAsync(string providerName, string providerKey) public virtual async Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey) .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
} }
} }
} }

11
modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs

@ -44,7 +44,8 @@ namespace Volo.Abp.Identity.MongoDB
userId, userId,
userName, userName,
clientId, clientId,
correlationId correlationId,
cancellationToken
); );
return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc") return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc")
@ -74,7 +75,8 @@ namespace Volo.Abp.Identity.MongoDB
userId, userId,
userName, userName,
clientId, clientId,
correlationId correlationId,
cancellationToken
); );
return await query.As<IMongoQueryable<IdentitySecurityLog>>() return await query.As<IMongoQueryable<IdentitySecurityLog>>()
@ -98,9 +100,10 @@ namespace Volo.Abp.Identity.MongoDB
Guid? userId = null, Guid? userId = null,
string userName = null, string userName = null,
string clientId = null, string clientId = null,
string correlationId = null) string correlationId = null,
CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync()) return (await GetMongoQueryableAsync(cancellationToken))
.WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime.Value) .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime.Value)
.WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime < endTime.Value.AddDays(1).Date) .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime < endTime.Value.AddDays(1).Date)
.WhereIf(!applicationName.IsNullOrWhiteSpace(), .WhereIf(!applicationName.IsNullOrWhiteSpace(),

9
modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs

@ -21,7 +21,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
public async Task<List<PersistedGrant>> GetListAsync(string subjectId, string sessionId, string clientId, string type, bool includeDetails = false, public async Task<List<PersistedGrant>> GetListAsync(string subjectId, string sessionId, string clientId, string type, bool includeDetails = false,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return await (await FilterAsync(subjectId, sessionId, clientId, type)) return await (await FilterAsync(subjectId, sessionId, clientId, type, cancellationToken))
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }
@ -57,7 +57,7 @@ namespace Volo.Abp.IdentityServer.MongoDB
string type = null, string type = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var persistedGrants = await (await FilterAsync(subjectId, sessionId, clientId, type)) var persistedGrants = await (await FilterAsync(subjectId, sessionId, clientId, type, cancellationToken))
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
foreach (var persistedGrant in persistedGrants) foreach (var persistedGrant in persistedGrants)
@ -86,9 +86,10 @@ namespace Volo.Abp.IdentityServer.MongoDB
string subjectId, string subjectId,
string sessionId, string sessionId,
string clientId, string clientId,
string type) string type,
CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync()) return (await GetMongoQueryableAsync(cancellationToken))
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!subjectId.IsNullOrWhiteSpace(), x => x.SubjectId == subjectId) .WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!subjectId.IsNullOrWhiteSpace(), x => x.SubjectId == subjectId)
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!sessionId.IsNullOrWhiteSpace(), x => x.SessionId == sessionId) .WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!sessionId.IsNullOrWhiteSpace(), x => x.SessionId == sessionId)
.WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!clientId.IsNullOrWhiteSpace(), x => x.ClientId == clientId) .WhereIf<PersistedGrant, IMongoQueryable<PersistedGrant>>(!clientId.IsNullOrWhiteSpace(), x => x.ClientId == clientId)

18
modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -7,10 +8,21 @@ namespace Volo.Abp.SettingManagement
{ {
public interface ISettingRepository : IBasicRepository<Setting, Guid> public interface ISettingRepository : IBasicRepository<Setting, Guid>
{ {
Task<Setting> FindAsync(string name, string providerName, string providerKey); Task<Setting> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<Setting>> GetListAsync(string providerName, string providerKey); Task<List<Setting>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<Setting>> GetListAsync(string[] names, string providerName, string providerKey); Task<List<Setting>> GetListAsync(
string[] names,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
} }
} }

29
modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
@ -8,36 +9,48 @@ using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.SettingManagement.EntityFrameworkCore namespace Volo.Abp.SettingManagement.EntityFrameworkCore
{ {
public class EfCoreSettingRepository : EfCoreRepository<ISettingManagementDbContext, Setting, Guid>, ISettingRepository public class EfCoreSettingRepository : EfCoreRepository<ISettingManagementDbContext, Setting, Guid>,
ISettingRepository
{ {
public EfCoreSettingRepository(IDbContextProvider<ISettingManagementDbContext> dbContextProvider) public EfCoreSettingRepository(IDbContextProvider<ISettingManagementDbContext> dbContextProvider)
: base(dbContextProvider) : base(dbContextProvider)
{ {
} }
public virtual async Task<Setting> FindAsync(string name, string providerName, string providerKey) public virtual async Task<Setting> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.OrderBy(x => x.Id) .OrderBy(x => x.Id)
.FirstOrDefaultAsync( .FirstOrDefaultAsync(
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey,
); GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<Setting>> GetListAsync(string providerName, string providerKey) public virtual async Task<List<Setting>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.Where( .Where(
s => s.ProviderName == providerName && s.ProviderKey == providerKey s => s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(); ).ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<Setting>> GetListAsync(string[] names, string providerName, string providerKey) public virtual async Task<List<Setting>> GetListAsync(
string[] names,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetDbSetAsync()) return await (await GetDbSetAsync())
.Where( .Where(
s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(); ).ToListAsync(GetCancellationToken(cancellationToken));
} }
} }
} }

36
modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
@ -9,33 +10,46 @@ using Volo.Abp.MongoDB;
namespace Volo.Abp.SettingManagement.MongoDB namespace Volo.Abp.SettingManagement.MongoDB
{ {
public class MongoSettingRepository : MongoDbRepository<ISettingManagementMongoDbContext, Setting, Guid>, ISettingRepository public class MongoSettingRepository : MongoDbRepository<ISettingManagementMongoDbContext, Setting, Guid>,
ISettingRepository
{ {
public MongoSettingRepository(IMongoDbContextProvider<ISettingManagementMongoDbContext> dbContextProvider) public MongoSettingRepository(IMongoDbContextProvider<ISettingManagementMongoDbContext> dbContextProvider)
: base(dbContextProvider) : base(dbContextProvider)
{ {
} }
public virtual async Task<Setting> FindAsync(string name, string providerName, string providerKey) public virtual async Task<Setting> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.OrderBy(x => x.Id) .OrderBy(x => x.Id)
.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); .FirstOrDefaultAsync(
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey,
GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<Setting>> GetListAsync(string providerName, string providerKey) public virtual async Task<List<Setting>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey) .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<Setting>> GetListAsync(string[] names, string providerName, string providerKey) public virtual async Task<List<Setting>> GetListAsync(
string[] names,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey) .Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(); .ToListAsync(GetCancellationToken(cancellationToken));
} }
} }
} }

75
npm/ng-packs/packages/core/src/lib/tests/tree-utils.spec.ts

@ -1,4 +1,9 @@
import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils'; import {
BaseTreeNode,
createTreeFromList,
createTreeNodeFilterCreator,
TreeNode,
} from '../utils/tree-utils';
const LIST_1 = [ const LIST_1 = [
{ id: 1, pid: null }, { id: 1, pid: null },
@ -38,6 +43,42 @@ const TREE_3 = [
], ],
}, },
]; ];
const SOURCE_TREE: TreeNode<SearchModel>[] = [
{
id: 1,
pid: null,
isLeaf: false,
name: 'foo',
children: [
{
id: 2,
pid: 1,
name: 'bar',
isLeaf: false,
children: [{ id: 3, pid: 2, name: 'qux', isLeaf: true, children: [] }],
},
{ id: 4, pid: 1, name: 'baz', isLeaf: true, children: [] },
{ id: 5, pid: 1, name: 'quux', isLeaf: true, children: [] },
],
},
];
const RESULT_TREE_1 = [
{ id: 3, pid: 2, name: 'qux', isLeaf: true, children: [] },
{ id: 5, pid: 1, name: 'quux', isLeaf: true, children: [] },
];
const RESULT_TREE_2 = [{ id: 5, pid: 1, name: 'quux', isLeaf: true, children: [] }];
const RESULT_TREE_3 = [
{
id: 2,
pid: 1,
name: 'bar',
isLeaf: false,
children: [{ id: 3, pid: 2, name: 'qux', isLeaf: true, children: [] }],
},
{ id: 4, pid: 1, name: 'baz', isLeaf: true, children: [] },
];
const RESULT_TREE_4 = [{ id: 4, pid: 1, name: 'baz', isLeaf: true, children: [] }];
describe('Tree Utils', () => { describe('Tree Utils', () => {
describe('createTreeFromList', () => { describe('createTreeFromList', () => {
test.each` test.each`
@ -56,6 +97,23 @@ describe('Tree Utils', () => {
expect(removeParents(tree)).toEqual(expected); expect(removeParents(tree)).toEqual(expected);
}); });
}); });
describe('createTreeNodeFilterCreator', () => {
test.each`
search | expected
${'qu'} | ${RESULT_TREE_1}
${'quu'} | ${RESULT_TREE_2}
${'ba'} | ${RESULT_TREE_3}
${'baz'} | ${RESULT_TREE_4}
`(
'should return $expected when $search is searched',
({ search, expected }: TestCreateTreeNodeFilter) => {
const filter = createTreeNodeFilterCreator('name', String)(search);
expect(filter(SOURCE_TREE)).toEqual(expected);
},
);
});
}); });
function removeParents(tree: TreeNode<Model>[]) { function removeParents(tree: TreeNode<Model>[]) {
@ -72,6 +130,17 @@ interface TestCreateTreeFromList {
} }
interface Model { interface Model {
id: 1; id: number;
pid: null; pid?: number;
}
interface TestCreateTreeNodeFilter {
search: string;
expected: TreeNode<SearchModel>[];
}
interface SearchModel {
id: number;
pid?: number;
name: string;
} }

19
npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts

@ -54,6 +54,25 @@ export function createMapFromList<T extends object, R extends unknown>(
return map; return map;
} }
export function createTreeNodeFilterCreator<T extends object>(
key: keyof T,
mapperFn: (value: any) => string,
) {
return (search: string) => {
const regex = new RegExp('.*' + search + '.*', 'i');
return function collectNodes(nodes: TreeNode<T>[], matches = []) {
for (const node of nodes) {
if (regex.test(mapperFn(node[key]))) matches.push(node);
if (node.children.length) collectNodes(node.children, matches);
}
return matches;
};
};
}
export type TreeNode<T extends object> = { export type TreeNode<T extends object> = {
[K in keyof T]: T[K]; [K in keyof T]: T[K];
} & { } & {

Loading…
Cancel
Save