Browse Source

Merge branch 'dev' into RequireEmailVerificationToRegister

pull/21973/head
maliming 2 years ago
parent
commit
c5c60fbe65
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 6
      Directory.Packages.props
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  3. 6
      build/common.ps1
  4. 147
      docs/en/Blog-Posts/2025-01-21 v9_1_Preview/POST.md
  5. BIN
      docs/en/Blog-Posts/2025-01-21 v9_1_Preview/cover-image.png
  6. BIN
      docs/en/Blog-Posts/2025-01-21 v9_1_Preview/idle-session-settings.png
  7. BIN
      docs/en/Blog-Posts/2025-01-21 v9_1_Preview/lazy-expandable.png
  8. BIN
      docs/en/Blog-Posts/2025-01-21 v9_1_Preview/session-expiration-warning.png
  9. BIN
      docs/en/Blog-Posts/2025-01-21 v9_1_Preview/studio-switch-to-preview.png
  10. 46
      docs/en/Blog-Posts/2025-01-22 ABP_Now_Supports_MacOS_Intel/POST.md
  11. BIN
      docs/en/Blog-Posts/2025-01-22 ABP_Now_Supports_MacOS_Intel/abp-studio-macos-intel.png
  12. BIN
      docs/en/Blog-Posts/2025-01-22 ABP_Now_Supports_MacOS_Intel/cover-image.png
  13. BIN
      docs/en/Community-Articles/2025-01-23-Fixing-OpenIddict-Certificate-Issues/Load-User-Profile.jpg
  14. 77
      docs/en/Community-Articles/2025-01-23-Fixing-OpenIddict-Certificate-Issues/POST.md
  15. 9
      docs/en/deployment/configuring-openIddict.md
  16. 4
      docs/en/docs-nav.json
  17. 8
      docs/en/framework/architecture/best-practices/mongodb-integration.md
  18. 13
      docs/en/framework/architecture/domain-driven-design/repositories.md
  19. 8
      docs/en/guides/microservice-mongodb.md
  20. 2
      docs/en/modules/account-pro.md
  21. 59
      docs/en/release-info/migration-guides/MongoDB-Driver-2-to-3.md
  22. 7
      docs/en/release-info/migration-guides/abp-9-1.md
  23. 1
      docs/en/release-info/migration-guides/index.md
  24. 10
      docs/en/release-info/release-notes.md
  25. 16
      docs/en/release-info/road-map.md
  26. 14
      docs/en/studio/release-notes.md
  27. 3
      docs/en/studio/version-mapping.md
  28. 7
      docs/en/tutorials/book-store/part-07.md
  29. 4
      docs/en/tutorials/modular-crm/index.md
  30. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/toast/abp-toast.css
  31. 31
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/toast/abp-toast.js
  32. 24
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs
  33. 64
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs
  34. 47
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  35. 11
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs
  36. 53
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  37. 15
      framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs
  38. 2
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbDateTimeSerializer.cs
  39. 5
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs
  40. 1
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventInbox.cs
  41. 1
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventOutbox.cs
  42. 141
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs
  43. 72
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs
  44. 8
      framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj
  45. 5
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbFixture.cs
  46. 12
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs
  47. 1
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs
  48. 101
      modules/account/src/Volo.Abp.Account.HttpApi/Volo.Abp.Account.HttpApi.abppkg.analyze.json
  49. 41
      modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.abppkg.analyze.json
  50. 2
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json
  51. 39
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter.cs
  52. 18
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogInfoToAuditLogConverter.cs
  53. 9
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.abppkg.analyze.json
  54. 24
      modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs
  55. 6
      modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogEntityTypeFullNameConverter_Tests.cs
  56. 8
      modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.csproj
  57. 9
      modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/AuditLogEntityTypeFullNameConverter_Tests.cs
  58. 2
      modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/MongoDbFixture.cs
  59. 46
      modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter_Tests.cs
  60. 9
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.abppkg.analyze.json
  61. 5
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs
  62. 8
      modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo.Abp.BackgroundJobs.MongoDB.Tests.csproj
  63. 2
      modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo/Abp/BackgroundJobs/MongoDB/MongoDbFixture.cs
  64. 15
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo.Abp.BlobStoring.Database.EntityFrameworkCore.abppkg.analyze.json
  65. 4
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/MongoDbDatabaseBlobRepository.cs
  66. 2
      modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/MongoDB/MongoDbFixture.cs
  67. 8
      modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/Volo.Abp.BlobStoring.Database.MongoDB.Tests.csproj
  68. 2
      modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.abppkg.analyze.json
  69. 84
      modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.analyze.json
  70. 77
      modules/blogging/src/Volo.Blogging.Domain/Volo.Blogging.Domain.abppkg.analyze.json
  71. 39
      modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.abppkg.analyze.json
  72. 294
      modules/blogging/src/Volo.Blogging.HttpApi/Volo.Blogging.HttpApi.abppkg.analyze.json
  73. 2
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs
  74. 9
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs
  75. 13
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs
  76. 10
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs
  77. 3
      modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs
  78. 8
      modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.csproj
  79. 2
      modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo/Blogging/MongoDB/MongoDbFixture.cs
  80. 2
      modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/Volo.CmsKit.HttpApi.Host.abppkg.analyze.json
  81. 2
      modules/cms-kit/host/Volo.CmsKit.Web.Host/Volo.CmsKit.Web.Host.abppkg.analyze.json
  82. 196
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo.CmsKit.Admin.Application.Contracts.abppkg.analyze.json
  83. 136
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo.CmsKit.Common.Application.abppkg.analyze.json
  84. 11
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.abppkg.analyze.json
  85. 13
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json
  86. 13
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  87. 82
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo.CmsKit.Domain.abppkg.analyze.json
  88. 87
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo.CmsKit.EntityFrameworkCore.abppkg.analyze.json
  89. 4
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogFeatureRepository.cs
  90. 22
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs
  91. 13
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs
  92. 24
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Comments/MongoCommentRepository.cs
  93. 6
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/MarkedItems/MongoUserMarkedItemRepository.cs
  94. 15
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs
  95. 4
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Ratings/MongoRatingRepository.cs
  96. 6
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Reactions/MongoUserReactionRepository.cs
  97. 2
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs
  98. 17
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs
  99. 14
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo.CmsKit.Public.Application.Contracts.abppkg.analyze.json
  100. 41
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo.CmsKit.Public.Application.abppkg.analyze.json

6
Directory.Packages.props

@ -37,6 +37,10 @@
<PackageVersion Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" />
<PackageVersion Include="MongoSandbox.Core" Version="1.0.1" />
<PackageVersion Include="MongoSandbox6.runtime.linux-x64" Version="1.0.1" />
<PackageVersion Include="MongoSandbox6.runtime.osx-x64" Version="1.0.1" />
<PackageVersion Include="MongoSandbox6.runtime.win-x64" Version="1.0.1" />
<PackageVersion Include="FluentValidation" Version="11.10.0" /> <PackageVersion Include="FluentValidation" Version="11.10.0" />
<PackageVersion Include="Google.Cloud.Storage.V1" Version="4.10.0" /> <PackageVersion Include="Google.Cloud.Storage.V1" Version="4.10.0" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.17" /> <PackageVersion Include="Hangfire.AspNetCore" Version="1.8.17" />
@ -111,7 +115,7 @@
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" /> <PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" /> <PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
<PackageVersion Include="Minio" Version="6.0.3" /> <PackageVersion Include="Minio" Version="6.0.3" />
<PackageVersion Include="MongoDB.Driver" Version="2.29.0" /> <PackageVersion Include="MongoDB.Driver" Version="3.1.0" />
<PackageVersion Include="NEST" Version="7.17.5" /> <PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" /> <PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -535,7 +535,7 @@
"WhenShouldIRenewMyLicenseExplanation3": "{0} for Business and Enterprise Licenses;", "WhenShouldIRenewMyLicenseExplanation3": "{0} for Business and Enterprise Licenses;",
"WhenShouldIRenewMyLicenseExplanation4": "However, if you renew your license more than {0} days after the expiry date, the renewal price will be the same as the initial purchase price of the license, with no discounts applied to your renewal.", "WhenShouldIRenewMyLicenseExplanation4": "However, if you renew your license more than {0} days after the expiry date, the renewal price will be the same as the initial purchase price of the license, with no discounts applied to your renewal.",
"DoesTheSubscriptionRenewAutomaticallyExplanationAutoRenewal": "ABP Platform allows you to auto-renew your license. This is an optional free service. You can toggle this feature when you purchase a new license or later enable it from your <a href=\"{0}\">organization management page</a>. If you want to turn on or off the auto-renewal, visit the <a href=\"{0}\">organization management page</a>, go to the 'Payments Method' section and either check or uncheck the 'Automatic Renewal' checkbox. When you turn off the auto-renewal feature, it will be your responsibility to renew your license manually.", "DoesTheSubscriptionRenewAutomaticallyExplanationAutoRenewal": "ABP Platform allows you to auto-renew your license. This is an optional free service. You can toggle this feature when you purchase a new license or later enable it from your <a href=\"{0}\">organization management page</a>. If you want to turn on or off the auto-renewal, visit the <a href=\"{0}\">organization management page</a>, go to the 'Payments Method' section and either check or uncheck the 'Automatic Renewal' checkbox. When you turn off the auto-renewal feature, it will be your responsibility to renew your license manually.",
"TrialPlanExplanation": "Yes, to start your free trial, please contact <a href=\"mailto:marketing@volosoft.com?subject=Trial License Request\">marketing@volosoft.com</a>. We also offer a 30-day money-back guarantee for the Team license, with no questions asked! You can request a full refund within the first 30 days of purchasing the license. For Business and Enterprise licenses, we provide a 60% refund if requested within 30 days of purchase. This policy is due to the inclusion of the full source code for all modules and themes in the Business and Enterprise licenses.", "TrialPlanExplanation": "Yes, to start your free trial, please contact <a href=\"mailto:sales@volosoft.com?subject=Trial License Request\">sales@volosoft.com</a>. We also offer a 30-day money-back guarantee for the Team license, with no questions asked! You can request a full refund within the first 30 days of purchasing the license. For Business and Enterprise licenses, we provide a 60% refund if requested within 30 days of purchase. This policy is due to the inclusion of the full source code for all modules and themes in the Business and Enterprise licenses.",
"BlazoriseLicenseExplanation": "We have an agreement between Volosoft and Megabit, according to which the Blazorise license is bundled with the ABP Platform’s commercial licenses. Therefore, our paid users do not need to purchase an additional Blazorise license.", "BlazoriseLicenseExplanation": "We have an agreement between Volosoft and Megabit, according to which the Blazorise license is bundled with the ABP Platform’s commercial licenses. Therefore, our paid users do not need to purchase an additional Blazorise license.",
"HowToUpgradeExplanation1": "When you create a new application using the ABP startup templates, all the modules and themes are used as NuGet and NPM packages. This setup allows for easy upgrades to newer versions of the packages.", "HowToUpgradeExplanation1": "When you create a new application using the ABP startup templates, all the modules and themes are used as NuGet and NPM packages. This setup allows for easy upgrades to newer versions of the packages.",
"HowToUpgradeExplanation2": "In addition to the standard NuGet/NPM upgrades, <a href=\"{0}\">ABP CLI</a> provides an <strong>update</strong> command that automatically finds and upgrades all ABP-related packages in your solution.", "HowToUpgradeExplanation2": "In addition to the standard NuGet/NPM upgrades, <a href=\"{0}\">ABP CLI</a> provides an <strong>update</strong> command that automatically finds and upgrades all ABP-related packages in your solution.",

6
build/common.ps1

@ -34,11 +34,13 @@ if ($full -eq "-f")
"../templates/module/aspnet-core", "../templates/module/aspnet-core",
"../templates/app/aspnet-core", "../templates/app/aspnet-core",
"../templates/console", "../templates/console",
"../templates/wpf",
"../templates/app-nolayers/aspnet-core", "../templates/app-nolayers/aspnet-core",
"../abp_io/AbpIoLocalization", "../abp_io/AbpIoLocalization",
"../source-code" "../source-code"
) )
if ($env:OS -eq "Windows_NT") {
$solutionPaths += "../templates/wpf"
}
}else{ }else{
Write-host "" Write-host ""
Write-host ":::::::::::::: !!! You are in development mode !!! ::::::::::::::" -ForegroundColor red -BackgroundColor yellow Write-host ":::::::::::::: !!! You are in development mode !!! ::::::::::::::" -ForegroundColor red -BackgroundColor yellow

147
docs/en/Blog-Posts/2025-01-21 v9_1_Preview/POST.md

@ -0,0 +1,147 @@
# ABP Platform 9.1 RC Has Been Released
We are happy to release [ABP](https://abp.io) version **9.1 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
Try this version and provide feedback for a more stable version of ABP v9.1! Thanks to you in advance.
## Get Started with the 9.1 RC
You can check the [Get Started page](https://abp.io/get-started) to see how to get started with ABP. You can either download [ABP Studio](https://abp.io/get-started#abp-studio-tab) (**recommended**, if you prefer a user-friendly GUI application - desktop application) or use the [ABP CLI](https://abp.io/docs/latest/cli).
By default, ABP Studio uses stable versions to create solutions. Therefore, if you want to create a solution with a preview version, first you need to create a solution and then switch your solution to the preview version from the ABP Studio UI:
![studio-switch-to-preview.png](studio-switch-to-preview.png)
## Migration Guide
There are no breaking changes in this version that would affect your application. Only you might need to update some constant names due to the OpenIddict 6.0 upgrade, which is explained in the [OpenIddict 6.0 migration guide](https://abp.io/docs/9.1/release-info/migration-guides/openiddict5-to-6).
## What's New with ABP v9.1?
In this section, I will introduce some major features released in this version.
Here is a brief list of titles explained in the next sections:
* Upgraded to Angular 19
* Upgraded to OpenIddict 6.0
* New Blazor WASM Bundling System
* Idle Session Warning
* Lazy Expandable Feature for Documentation
### Upgraded to Angular 19
We've upgraded the Angular templates and packages to **Angular 19**. This upgrade brings the latest features and improvements from the Angular ecosystem to ABP-based applications, including better performance and development experience.
### Upgraded to OpenIddict 6.0
OpenIddict 6.0 has been released and we've upgraded the OpenIddict packages to version 6.0 in ABP 9.1. This brings enhanced security features and improved authentication capabilities. The migration is straightforward and mainly involves updating some constant names:
- `OpenIddictConstants.Permissions.Endpoints.Logout` is now `OpenIddictConstants.Permissions.Endpoints.EndSession`
- `OpenIddictConstants.Permissions.Endpoints.Device` is now `OpenIddictConstants.Permissions.Endpoints.DeviceAuthorization`
If you're using IdentityModel packages directly, you'll need to upgrade them to the latest stable version (8.3.0). This update ensures your applications stay current with the latest security standards and best practices.
> Please refer to the [OpenIddict 6.0 migration guide](https://abp.io/docs/9.1/release-info/migration-guides/openiddict5-to-6) for more information.
### New Blazor WASM Bundling System
We've implemented a new bundling system for Blazor WebAssembly applications that eliminates the need to manually run the `abp bundle` command. This system automatically handles JavaScript and CSS file bundling at runtime, significantly improving both development experience and application loading performance.
**Key improvements include:**
- Automatic bundling of JavaScript and CSS files without manual intervention
- Dynamic file generation through the host application
- Better integration with the ABP module system
- Improved asset management through virtual file system
The new system is particularly beneficial for modular applications, as it allows modules to contribute their assets automatically to the global bundles. This results in a more maintainable and efficient asset management system for Blazor WebAssembly applications.
> Please refer to [this documentation](https://abp.io/docs/9.1/framework/ui/blazor/global-scripts-styles) for more information.
### Idle Session Warning
We've introduced a new idle session warning feature for the [Account (Pro) Module](https://abp.io/docs/latest/modules/account-pro) that helps manage user sessions more effectively. This security enhancement automatically monitors user activity and manages session timeouts in a user-friendly way.
![idle-session-settings.png](idle-session-settings.png)
The feature can be easily configured through the administration interface, where administrators can:
- Enable/disable the idle session timeout
- Set custom timeout duration in minutes
- Configure when users should be signed out
When a user becomes inactive for the configured duration, they'll receive a warning dialog:
![session-expiration-warning.png](session-expiration-warning.png)
**Key features and behaviors:**
- Tracks real user activity (mouse movements, keyboard presses) across all tabs
- Works on a per-browser session basis - affects all tabs of the same session
- Maintains session if user is active in any tab of the application
- Provides a countdown timer before automatic sign-out
- Offers options to "Stay signed in" or "Sign out now"
This feature significantly improves application security while maintaining a smooth user experience by preventing unexpected session expirations and data loss.
### Lazy Expandable Feature for Documentation
We've introduced a new lazy expandable feature to the documentation system that significantly improves navigation through large documentation sections. This enhancement addresses common challenges when dealing with extensive documentation hierarchies by introducing smart menu management.
**Key benefits and features:**
- **Cleaner Navigation:** The menu stays concise by hiding sub-items until they're needed, reducing visual clutter
- **Better Performance:** Reduces the initial load of the navigation tree by loading sub-items on demand
- **Improved Search Experience:** Makes filtering documentation items more efficient by showing only relevant top-level items
- **Context-Aware Expansion:** Automatically expands relevant sections when viewing specific documentation pages
The feature works by marking certain documentation sections as "lazy expandable" in the navigation configuration. When users navigate to a document within a lazy expandable section, the system automatically expands the relevant menu items while keeping other sections collapsed.
This improvement is particularly valuable for complex documentation areas like tutorials, solution templates, and extensive module documentation, where having all navigation items visible at once could be overwhelming.
An example of lazy expandable feature from the [ABP's BookStore Tutorial](https://abp.io/docs/latest/tutorials/book-store/part-01):
```json
{
"text": "Book Store Application",
"isLazyExpandable": true,
"path": "tutorials/book-store",
"items": [
{
"text": "Overview",
"path": "tutorials/book-store",
"isIndex": true
},
//other items...
]
}
```
![lazy-expandable.png](lazy-expandable.png)
### Others
Some other highlights from this release:
* Updated Iyzico NuGet packages to the latest version, which is used in the [ABP's Payment Module](https://abp.io/docs/latest/modules/payment#payment-module-pro).
* Removed optional _secondaryIds_ from path. See: [#21307](https://github.com/abpframework/abp/pull/21307)
* [CMS Kit Pro](https://abp.io/docs/latest/modules/cms-kit-pro): Added automatic deletion of comments when a blog post is deleted - comments are now automatically removed when their associated blog post is deleted.
* Avoiding global blocking in distributed event handlers (See [#21716](https://github.com/abpframework/abp/pull/21716)).
## Community News
### New ABP Community Articles
There are exciting articles contributed by the ABP community as always. I will highlight some of them here:
* [Integrating ABP Modules in Your ASP.NET Core Web API Project. A Step-by-Step Guide](https://abp.io/community/articles/integrating-abp-modules-in-your-asp.net-core-web-api-project.-a-stepbystep-guide-jtbyosnr) by [Sajankumar Vijayan](https://abp.io/community/members/connect)
* [ABP Framework: Background Jobs vs Background Workers](https://abp.io/community/articles/abp-framework-background-jobs-vs-background-workers-when-to-use-which-t98pzjv6) — When to Use Which? by [Alper Ebiçoğlu](https://twitter.com/alperebicoglu)
* [The new Unit Test structure in ABP application](https://abp.io/community/articles/the-new-unit-test-structure-in-abp-application-4vvvp2oy) by [Liming Ma](https://github.com/maliming)
* [How to Use OpenAI API with ABP Framework](https://abp.io/community/articles/how-to-use-openai-api-with-abp-framework-rsfvihla) by [Berkan Şaşmaz](https://github.com/berkansasmaz)
Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community.
## Conclusion
This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://abp.io/docs/9.1/release-info/road-map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v9.1 RC and provide feedback to help us release a more stable version.
Thanks for being a part of this community!

BIN
docs/en/Blog-Posts/2025-01-21 v9_1_Preview/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 KiB

BIN
docs/en/Blog-Posts/2025-01-21 v9_1_Preview/idle-session-settings.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
docs/en/Blog-Posts/2025-01-21 v9_1_Preview/lazy-expandable.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/en/Blog-Posts/2025-01-21 v9_1_Preview/session-expiration-warning.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/en/Blog-Posts/2025-01-21 v9_1_Preview/studio-switch-to-preview.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

46
docs/en/Blog-Posts/2025-01-22 ABP_Now_Supports_MacOS_Intel/POST.md

@ -0,0 +1,46 @@
# ABP Studio Now Supports MacOS Intel 🚀
We are excited to announce that [ABP Studio, our cross-platform desktop application for ABP developers](https://abp.io/studio), now supports Intel-based Mac computers!
This addition expands our platform compatibility, ensuring that developers using Intel-powered Macs can also benefit from the powerful features of ABP Studio.
## What is ABP Studio?
For those who aren't familiar, [ABP Studio](https://abp.io/studio) is a powerful desktop application that makes ABP development faster and easier. It offers:
* Easy creation of new solutions (from simple applications to microservices)
* Visual architecture management for modular-monolith and microservice solutions
* Solution exploration tools for entities, services, and HTTP APIs
* Simplified running, debugging and monitoring of multi-application or microservice solutions
* Kubernetes cluster integration capabilities
* and more...
## Extended Platform Support
ABP Studio has been proudly supporting multiple platforms, and we're excited to add MacOS Intel to the our list of supported architectures. You can now use ABP Studio on:
* Windows x64
* Windows ARM
* MacOS Apple Silicon (M1/M2/M3)
* MacOS Intel **(New!)**
## Why This Matters
This update is particularly important for developers who are using Intel-based Mac computers. Previously, ABP Studio was only available for Apple Silicon Macs (for MacOS), but we understand that many developers are still using Intel-based Macs. With this release, we're ensuring that all Mac users can access our development tools, regardless of their processor architecture.
## Getting Started
Installing ABP Studio on your Intel-based Mac is straightforward:
1. Go to [abp.io/studio](https://abp.io/studio)
2. Click on the download button and select "MacOS Intel" from the dropdown menu
3. Once downloaded, open the installer package
4. Follow the installation wizard to complete the setup
![ABP Studio Download Page](abp-studio-macos-intel.png)
## Conclusion
As ABP team, we're always looking for ways to improve the developer experience. By supporting Intel-based Macs, we're ensuring that all Mac users can access our development tools, regardless of their processor architecture.
Stay tuned for more updates and enhancements as we continue to optimize ABP Studio and please provide us with your invaluable feedback. Thanks in advance!

BIN
docs/en/Blog-Posts/2025-01-22 ABP_Now_Supports_MacOS_Intel/abp-studio-macos-intel.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

BIN
docs/en/Blog-Posts/2025-01-22 ABP_Now_Supports_MacOS_Intel/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 KiB

BIN
docs/en/Community-Articles/2025-01-23-Fixing-OpenIddict-Certificate-Issues/Load-User-Profile.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

77
docs/en/Community-Articles/2025-01-23-Fixing-OpenIddict-Certificate-Issues/POST.md

@ -0,0 +1,77 @@
# Fixing OpenIddict Certificate Issues in IIS or Azure
When deploying an ABP application with OpenIddict to IIS or Azure, you may encounter issues with loading PFX/PKCS12 certificates. This article explains how to properly configure certificate loading to ensure it works correctly in these environments.
## The Problem
When running under IIS or Azure, the application pool identity may not have sufficient permissions to access certificate private keys. This commonly results in errors such as:
- `System.Security.Cryptography.CryptographicException: Access denied.`
- `WindowsCryptographicException: Access is denied.`
- `System.Security.Cryptography.CryptographicException: The system cannot find the file specified.`
## The Solution
### Using AddDevelopmentEncryptionAndSigningCertificate
For development environments using `DevelopmentEncryptionAndSigningCertificate`, you must configure the application pool to load a user profile.
> Note: We strongly recommend using `DevelopmentEncryptionAndSigningCertificate` only in development environments. For production, always create and use a separate certificate.
![Application Pool Configuration](Load-User-Profile.jpg)
### Using AddProductionEncryptionAndSigningCertificate
The ABP OpenIddict module provides an `AddProductionEncryptionAndSigningCertificate` extension method. By default, the template project attempts to load an `openiddict.pfx` certificate in production environments.
To ensure proper certificate loading in IIS or Azure, you need to specify appropriate `X509KeyStorageFlags` when calling this method:
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
if (!hostingEnvironment.IsDevelopment())
{
PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
options.AddDevelopmentEncryptionAndSigningCertificate = false;
});
PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
{
var flag = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.EphemeralKeySet;
serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", "YourCertificatePassword", flag);
});
}
}
```
## Understanding X509KeyStorageFlags
The configuration uses two important flags:
* `X509KeyStorageFlags.MachineKeySet`: Specifies that the key belongs to the local computer key store, binding the key pair's lifecycle to the computer rather than a specific user.
* `X509KeyStorageFlags.EphemeralKeySet`: Indicates that the key will be stored only in memory and not persisted to disk or key store, enhancing security for runtime-only certificate requirements.
Using these flags in combination helps prevent permission-related issues in IIS and Azure environments.
## Troubleshooting Guide
If you continue to experience issues, verify the following:
* Confirm that the certificate password is correct
* Verify that the `openiddict.pfx` file exists in your deployment
* Ensure the certificate is valid - you can generate a new one using:
```bash
dotnet dev-certs https -v -ep openiddict.pfx -p YourCertificatePassword
```
* Check the stdout logs for related errors (See [how to get stdout-log](https://abp.io/docs/latest/solution-templates/layered-web-application/deployment/deployment-iis?UI=Blazor&DB=EF&Tiered=No#how-to-get-stdout-log))
## References
- [ABP OpenIddict Deployment](https://abp.io/docs/latest/solution-templates/layered-web-application/deployment/openiddict-deployment)
- [ABP IIS Deployment](https://abp.io/docs/latest/solution-templates/layered-web-application/deployment/deployment-iis)
- [ABP Azure Deployment](https://abp.io/docs/latest/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment)
- [How to Generate a New Certificate](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-dev-certs#how-to-generate-a-new-certificate)
- [Load User Profile in IIS](https://learn.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities#load-user-profile-for-an-application-pool)

9
docs/en/deployment/configuring-openIddict.md

@ -50,4 +50,13 @@ You can use the `dotnet dev-certs https -v -ep openiddict.pfx -p 00000000-0000-0
> If you encounter a deployment error on IIS that says **File not found** even though the file exists, it is recommended to set the application pool’s advanced settings **Load User Profile** to **True** to resolve the issue. > If you encounter a deployment error on IIS that says **File not found** even though the file exists, it is recommended to set the application pool’s advanced settings **Load User Profile** to **True** to resolve the issue.
> The `X509KeyStorageFlags.MachineKeySet` and `X509KeyStorageFlags.EphemeralKeySet` flags can be set in the `AddProductionEncryptionAndSigningCertificate` method for IIS deployments. For example:
```csharp
serverBuilder.AddProductionEncryptionAndSigningCertificate(
"openiddict.pfx",
"your-password",
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.EphemeralKeySet);
```
For more information, please refer to: https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-certificate-recommended-for-production-ready-scenarios For more information, please refer to: https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-certificate-recommended-for-production-ready-scenarios

4
docs/en/docs-nav.json

@ -2292,6 +2292,10 @@
{ {
"text": "Tenant impersonation & User impersonation", "text": "Tenant impersonation & User impersonation",
"path": "modules/account/impersonation.md" "path": "modules/account/impersonation.md"
},
{
"text": "Idle Session Timeout",
"path": "modules/account/idle-session-timeout.md"
} }
] ]
}, },

8
docs/en/framework/architecture/best-practices/mongodb-integration.md

@ -114,7 +114,7 @@ public async Task<IdentityUser> FindByNormalizedUserNameAsync(
bool includeDetails = true, bool includeDetails = true,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync()) return await (await GetQueryableAsync())
.FirstOrDefaultAsync( .FirstOrDefaultAsync(
u => u.NormalizedUserName == normalizedUserName, u => u.NormalizedUserName == normalizedUserName,
GetCancellationToken(cancellationToken) GetCancellationToken(cancellationToken)
@ -125,10 +125,10 @@ public async Task<IdentityUser> FindByNormalizedUserNameAsync(
`GetCancellationToken` fallbacks to the `ICancellationTokenProvider.Token` to obtain the cancellation token if it is not provided by the caller code. `GetCancellationToken` fallbacks to the `ICancellationTokenProvider.Token` to obtain the cancellation token if it is not provided by the caller code.
* **Do** ignore the `includeDetails` parameters for the repository implementation since MongoDB loads the aggregate root as a whole (including sub collections) by default. * **Do** ignore the `includeDetails` parameters for the repository implementation since MongoDB loads the aggregate root as a whole (including sub collections) by default.
* **Do** use the `GetMongoQueryableAsync()` method to obtain an `IQueryable<TEntity>` to perform queries wherever possible. Because; * **Do** use the `GetQueryableAsync()` method to obtain an `IQueryable<TEntity>` to perform queries wherever possible. Because;
* `GetMongoQueryableAsync()` method automatically uses the `ApplyDataFilters` method to filter the data based on the current data filters (like soft delete and multi-tenancy). * `GetQueryableAsync()` method automatically uses the `ApplyDataFilters` method to filter the data based on the current data filters (like soft delete and multi-tenancy).
* Using `IQueryable<TEntity>` makes the code as much as similar to the EF Core repository implementation and easy to write and read. * Using `IQueryable<TEntity>` makes the code as much as similar to the EF Core repository implementation and easy to write and read.
* **Do** implement data filtering if it is not possible to use the `GetMongoQueryable()` method. * **Do** implement data filtering if it is not possible to use the `GetQueryableAsync()` method.
## Module Class ## Module Class

13
docs/en/framework/architecture/domain-driven-design/repositories.md

@ -393,19 +393,6 @@ This method is suggested;
* If you are developing an application and you **don't plan to change** EF Core in the future, or you can **tolerate** it if you need to change it later. We believe that's reasonable if you are developing a final application. * If you are developing an application and you **don't plan to change** EF Core in the future, or you can **tolerate** it if you need to change it later. We believe that's reasonable if you are developing a final application.
#### MongoDB Case
If you are using [MongoDB](../../data/mongodb), you need to add the [Volo.Abp.MongoDB](https://www.nuget.org/packages/Volo.Abp.MongoDB) NuGet package to your project. Even in this case, you can't directly use async LINQ extensions (like `ToListAsync`) because MongoDB doesn't provide async extension methods for `IQueryable<T>`, but provides for `IMongoQueryable<T>`. You need to cast the query to `IMongoQueryable<T>` first to be able to use the async extension methods.
**Example: Cast `IQueryable<T>` to `IMongoQueryable<T>` and use `ToListAsync()`**
````csharp
var queryable = await _personRepository.GetQueryableAsync();
var people = ((IMongoQueryable<Person>) queryable
.Where(p => p.Name.Contains(nameFilter)))
.ToListAsync();
````
### Option-2: Use the IRepository Async Extension Methods ### Option-2: Use the IRepository Async Extension Methods
ABP provides async extension methods for the repositories, just similar to async LINQ extension methods. ABP provides async extension methods for the repositories, just similar to async LINQ extension methods.

8
docs/en/guides/microservice-mongodb.md

@ -97,9 +97,9 @@ Here we use `BookStore.ProductService` project as an example:
int skipCount = 0, int skipCount = 0,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var query = ApplyFilter(await GetMongoQueryableAsync(cancellationToken), filterText, name, priceMin, priceMax); var query = ApplyFilter(await GetQueryableAsync(cancellationToken), filterText, name, priceMin, priceMax);
query = query.OrderBy(string.IsNullOrWhiteSpace(sorting) ? ProductConsts.GetDefaultSorting(false) : sorting); query = query.OrderBy(string.IsNullOrWhiteSpace(sorting) ? ProductConsts.GetDefaultSorting(false) : sorting);
return await query.As<IMongoQueryable<Product>>().PageBy<Product, IMongoQueryable<Product>>(skipCount, maxResultCount).ToListAsync(cancellationToken); return await query.PageBy(skipCount, maxResultCount).ToListAsync(cancellationToken);
} }
public async Task<long> GetCountAsync( public async Task<long> GetCountAsync(
@ -109,8 +109,8 @@ Here we use `BookStore.ProductService` project as an example:
float? priceMax = null, float? priceMax = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var query = ApplyFilter(await GetMongoQueryableAsync(cancellationToken), filterText, name, priceMin, priceMax); var query = ApplyFilter(await GetQueryableAsync(cancellationToken), filterText, name, priceMin, priceMax);
return await query.As<IMongoQueryable<Product>>().LongCountAsync(GetCancellationToken(cancellationToken)); return await query.LongCountAsync(GetCancellationToken(cancellationToken));
} }
protected virtual IQueryable<Product> ApplyFilter( protected virtual IQueryable<Product> ApplyFilter(

2
docs/en/modules/account-pro.md

@ -358,4 +358,4 @@ This module doesn't define any additional distributed event. See the [standard d
* [Impersonation](./account/impersonation.md) * [Impersonation](./account/impersonation.md)
* [Linked Accounts](./account/linkedaccounts.md) * [Linked Accounts](./account/linkedaccounts.md)
* [Session Management](./account/session-management.md) * [Session Management](./account/session-management.md)
* [Idle Session Timeout](./account/idle-session-timeout.md)] * [Idle Session Timeout](./account/idle-session-timeout.md)

59
docs/en/release-info/migration-guides/MongoDB-Driver-2-to-3.md

@ -0,0 +1,59 @@
# Migrating from MongoDB Driver 2 to 3
## Introduction
The release of MongoDB Driver 3 includes numerous user-requested fixes and improvements that were deferred in previous versions due to backward compatibility concerns. It also features internal improvements to reduce technical debt and enhance maintainability. One major update is the removal of a significant portion of the public API (primarily from `MongoDB.Driver.Core`), which was not intended for public use. The removed APIs were marked as deprecated in version 2.30.0.
Please refer to the [upgrade guide](https://www.mongodb.com/docs/drivers/csharp/current/upgrade/v3/) for a complete list of breaking changes and upgrade guidelines.
## Repository Changes
Some method signatures in the `MongoDbRepository` class have been updated because the `IMongoQueryable` has been removed. The specific changes are as follows:
- The new `GetQueryableAsync` method has been added to return `IQueryable<TEntity>`.
- The `GetMongoQueryable` and `GetMongoQueryableAsync` methods return `IQueryable<TEntity>` instead of `IMongoQueryable<TEntity>`,
- The `GetMongoQueryable` and `GetMongoQueryableAsync` methods are marked as obsolete, You should use the new `GetQueryableAsync` method instead.
Please update your application by searching for and replacing these method calls.
> The return value of the `GetQueryableAsync` method is `IQueryable<TEntity>`, which can be used directly to perform queries, similar to EF Core. Remove all instances of `IMongoQueryable` in your project and replace them with `IQueryable`.
**Previous code example:**
```csharp
var myEntity = await (await GetMongoQueryableAsync()).As<IMongoQueryable<MyEntity>>().FirstOrDefaultAsync(x => x.Id == id);
```
**Updated code example:**
```csharp
var myEntity = await GetQueryableAsync().FirstOrDefaultAsync(x => x.Id == id);
```
## Unit Test Changes
Previously, we used the [EphemeralMongo](https://github.com/asimmon/ephemeral-mongo) library for unit testing. However, it does not support the latest version of [MongoDB.Driver 3.x](https://github.com/mongodb/mongo-go-driver). You should replace it with [MongoSandbox](https://github.com/wassim-k/MongoSandbox).
In your unit test project files, replace the following:
```xml
<PackageReference Include="EphemeralMongo.Core" Version="1.1.3" />
<PackageReference Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
```
With:
```xml
<PackageReference Include="MongoSandbox.Core" Version="1.0.1" />
<PackageReference Include="MongoSandbox6.runtime.linux-x64" Version="1.0.1" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="MongoSandbox6.runtime.osx-x64" Version="1.0.1" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="MongoSandbox6.runtime.win-x64" Version="1.0.1" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
```
In your unit test classes, replace `using EphemeralMongo` with `using MongoSandbox`.
## Official Upgrade Guide
We recommend reviewing the [upgrade guide](https://www.mongodb.com/docs/drivers/csharp/current/upgrade/v3/) for MongoDB Driver 3 to ensure a smooth migration process.

7
docs/en/release-info/migration-guides/abp-9-1.md

@ -0,0 +1,7 @@
# ABP Version 9.1 Migration Guide
This document is a guide for upgrading ABP v9.0 solutions to ABP v9.1. There are no breaking changes in this version that would affect your application.
Only you might need to update some constant names due to the OpenIddict 6.0 upgrade, which is explained in the following migration guide:
- [OpenIddict 5.x to 6.x Migration Guide](./openiddict5-to-6.md)

1
docs/en/release-info/migration-guides/index.md

@ -2,6 +2,7 @@
The following documents explain how to migrate your existing ABP applications. We write migration documents only if you need to take an action while upgrading your solution. Otherwise, you can easily upgrade your solution using the [abp update command](../upgrading.md). The following documents explain how to migrate your existing ABP applications. We write migration documents only if you need to take an action while upgrading your solution. Otherwise, you can easily upgrade your solution using the [abp update command](../upgrading.md).
- [9.0 to 9.1](abp-9-1.md)
- [8.x to 9.0](abp-9-0.md) - [8.x to 9.0](abp-9-0.md)
- [8.x to 8.3](abp-8-3.md) - [8.x to 8.3](abp-8-3.md)
- [8.1 to 8.2](abp-8-2.md) - [8.1 to 8.2](abp-8-2.md)

10
docs/en/release-info/release-notes.md

@ -4,6 +4,16 @@ This document contains **brief release notes** for each release. Release notes o
> If you want to read the release notes for each ABP Studio release, check it out from [here](../studio/release-notes.md). > If you want to read the release notes for each ABP Studio release, check it out from [here](../studio/release-notes.md).
## 9.1 (2025-01-16)
This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/blog/abp-9-1-release-candidate)** for the v9.1 release.
* Upgraded to Angular 19
* Upgraded to OpenIddict 6.0
* New Blazor WASM Bundling System
* Idle Session Warning
* Lazy Expandable Feature for Documentation System
## 9.0 (2024-11-19) ## 9.0 (2024-11-19)
See the detailed **[blog post / announcement](https://abp.io/blog/abp-9-0-stable-release-with-dotnet-9-0)** for the v9.0 release. See the detailed **[blog post / announcement](https://abp.io/blog/abp-9-0-stable-release-with-dotnet-9-0)** for the v9.0 release.

16
docs/en/release-info/road-map.md

@ -4,15 +4,13 @@ This document provides a road map, release schedule, and planned features for th
## Next Versions ## Next Versions
### v9.1 ### v9.2
The next version will be 9.1 and planned to release the stable 9.1 version in January 2025. We will be mostly working on the following topics: The next version will be 9.2 and planned to release the stable 9.2 version in June 2025. We will be mostly working on the following topics:
* Framework * Framework
* Lazy expandable feature for documentation
* Unify the bundling system of Blazor and MVC
* SSR support for the Angular UI
* Upgrading 3rd-party dependencies * Upgrading 3rd-party dependencies
* Enhancements in the core points
* ABP Suite * ABP Suite
* Define navigation properties without target string property dependency * Define navigation properties without target string property dependency
@ -32,12 +30,12 @@ The next version will be 9.1 and planned to release the stable 9.1 version in Ja
* Modular Monolith Application Startup Template * Modular Monolith Application Startup Template
* Application modules * Application modules
* Account module: Support mixed social/local login scenarios * Account module: Support mixed social/local login scenarios & enforcing email verification in wide aspect
* Idle session warning
* UI/UX improvements on existing application modules * UI/UX improvements on existing application modules
* New tutorials * Updating existing tutorials & documents (with other UI & DB options)
* Microservice development * Microservice development
* Modular monolith development
## Backlog Items ## Backlog Items
@ -64,7 +62,6 @@ ABP Platform provides many (free and commercial) [pre-built application modules]
* LeptonX theme: New layouts, styles and components * LeptonX theme: New layouts, styles and components
* CMS Kit module: Meta information for SEO, media gallery, RSS feed, content versioning, social media streams * CMS Kit module: Meta information for SEO, media gallery, RSS feed, content versioning, social media streams
* Identity module: Idle session warning
* Payment module: Invoice system * Payment module: Invoice system
* New module: User notification * New module: User notification
* New module: Dynamic dashboard * New module: Dynamic dashboard
@ -108,7 +105,6 @@ Here, are some of the important planned features for the next ABP Suite versions
* Allow to create pages instead of modals for CRUD page generation * Allow to create pages instead of modals for CRUD page generation
* View-only (detail view) modal/page for an entity * View-only (detail view) modal/page for an entity
* Export child/detail entity records as a part of export operation for a main (master) entity * Export child/detail entity records as a part of export operation for a main (master) entity
* Allow to accept attachments (files) for an entity
* Allow to add custom entity actions for an entity * Allow to add custom entity actions for an entity
* Allow to inherit from an existing entity class * Allow to inherit from an existing entity class
* Custom form layouts on CRUD page generation * Custom form layouts on CRUD page generation

14
docs/en/studio/release-notes.md

@ -2,6 +2,20 @@
This document contains **brief release notes** for each ABP Studio release. Release notes only include **major features** and **visible enhancements**. Therefore, they don't include all the development done in the related version. This document contains **brief release notes** for each ABP Studio release. Release notes only include **major features** and **visible enhancements**. Therefore, they don't include all the development done in the related version.
## 0.9.22 (2025-01-22)
* Allowed to display multiple installation notes.
* Showed **Inner Exceptions** in the Solution Runner side-panel
* Hidden logs when no selected application is present.
* Added full docker compose to template.
* Zipped microservice module template for better structuring the solution.
* Upgraded templates to version `9.0.4`.
## 0.9.21 (2025-01-09)
* Showed a db test connection message while testing the database connection.
* Fixed books sample's application service.
## 0.9.20 (2025-01-08) ## 0.9.20 (2025-01-08)
* Upgraded templates to version `9.0.3`. * Upgraded templates to version `9.0.3`.

3
docs/en/studio/version-mapping.md

@ -4,7 +4,8 @@ This document provides a general overview of the relationship between various ve
| **ABP Studio Version** | **ABP Version of Startup Template** | | **ABP Studio Version** | **ABP Version of Startup Template** |
|------------------------|---------------------------| |------------------------|---------------------------|
| 0.9.20 | 9.0.3 | | 0.9.22 | 9.0.4 |
| 0.9.20 - 0.9.21 | 9.0.3 |
| 0.9.17 to 0.9.19 | 9.0.2 | | 0.9.17 to 0.9.19 | 9.0.2 |
| 0.9.15 - 0.9.16 | 9.0.1 | | 0.9.15 - 0.9.16 | 9.0.1 |
| 0.9.9 to 0.9.14 | 9.0.0 | | 0.9.9 to 0.9.14 | 9.0.0 |

7
docs/en/tutorials/book-store/part-07.md

@ -180,7 +180,7 @@ public class MongoDbAuthorRepository
public async Task<Author> FindByNameAsync(string name) public async Task<Author> FindByNameAsync(string name)
{ {
var queryable = await GetMongoQueryableAsync(); var queryable = await GetQueryableAsync();
return await queryable.FirstOrDefaultAsync(author => author.Name == name); return await queryable.FirstOrDefaultAsync(author => author.Name == name);
} }
@ -190,14 +190,13 @@ public class MongoDbAuthorRepository
string sorting, string sorting,
string filter = null) string filter = null)
{ {
var queryable = await GetMongoQueryableAsync(); var queryable = await GetQueryableAsync();
return await queryable return await queryable
.WhereIf<Author, IMongoQueryable<Author>>( .WhereIf<Author, IQueryable<Author>>(
!filter.IsNullOrWhiteSpace(), !filter.IsNullOrWhiteSpace(),
author => author.Name.Contains(filter) author => author.Name.Contains(filter)
) )
.OrderBy(sorting) .OrderBy(sorting)
.As<IMongoQueryable<Author>>()
.Skip(skipCount) .Skip(skipCount)
.Take(maxResultCount) .Take(maxResultCount)
.ToListAsync(); .ToListAsync();

4
docs/en/tutorials/modular-crm/index.md

@ -29,8 +29,8 @@ This tutorial is organized as the following parts:
## Download the Source Code ## Download the Source Code
You can download the completed sample solution [here](https://github.com/abpframework/abp-samples/tree/master/ModularCRM). You can download the completed sample solution [here](https://github.com/abpframework/abp-samples/tree/master/ModularCrm).
## See Also ## See Also
* [Book Store: Web Application Development Tutorial](../book-store/index.md) * [Book Store: Web Application Development Tutorial](../book-store/index.md)

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/toast/abp-toast.css

@ -16,13 +16,13 @@
grid-template-columns: 35px 1fr; grid-template-columns: 35px 1fr;
gap: 5px; gap: 5px;
margin: 5px 0; margin: 5px 0;
padding: 7px; padding: 10px;
width: 350px; width: 350px;
user-select: none; user-select: none;
z-index: 9999; z-index: 9999;
color: #fff; color: #fff;
border-radius: 8px; border-radius: 8px;
font-size: 14px; font-size: 16px;
box-shadow: 0 0 20px 0 rgba(76, 87, 125, 0.02); box-shadow: 0 0 20px 0 rgba(76, 87, 125, 0.02);
animation: toastIn 0.3s ease-in-out; animation: toastIn 0.3s ease-in-out;
} }
@ -54,7 +54,7 @@
} }
.abp-toast-icon .icon { .abp-toast-icon .icon {
font-size: 32px; font-size: 30px;
} }
.abp-toast-content { .abp-toast-content {

31
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/toast/abp-toast.js

@ -73,12 +73,12 @@ AbpToastService.prototype.getIconClass = function(severity, options) {
} }
const icons = { const icons = {
success: 'bi-check', success: 'fa fa-check',
info: 'bi-info-circle', info: 'fa fa-info-circle',
warning: 'bi-exclamation-triangle', warning: 'fa fa-exclamation-triangle',
error: 'bi-shield-exclamation' error: 'fa fa-exclamation-circle'
}; };
return icons[severity] || 'bi-exclamation-triangle'; return icons[severity] || 'fa fa-exclamation-triangle';
}; };
// Create toast DOM element // Create toast DOM element
@ -88,14 +88,14 @@ AbpToastService.prototype.createToastElement = function(message, title, severity
const closeButton = options.closable !== false ? const closeButton = options.closable !== false ?
`<button class="abp-toast-close-button"> `<button class="abp-toast-close-button">
<i class="bi bi-x fs-4" aria-hidden="true"></i> <i class="fa fa-times" aria-hidden="true"></i>
</button>` : ''; </button>` : '';
const titleHtml = title ? `<div class="abp-toast-title">${title}</div>` : ''; const titleHtml = title ? `<div class="abp-toast-title">${title}</div>` : '';
toast.innerHTML = ` toast.innerHTML = `
<div class="abp-toast-icon"> <div class="abp-toast-icon">
<i class="bi ${this.getIconClass(severity, options)} icon" aria-hidden="true"></i> <i class="${this.getIconClass(severity, options)} icon" aria-hidden="true"></i>
</div> </div>
<div class="abp-toast-content"> <div class="abp-toast-content">
${closeButton} ${closeButton}
@ -189,28 +189,19 @@ AbpToastService.setDefaultOptions = function(options) {
var abp = abp || {}; var abp = abp || {};
(function () { (function () {
var toast;
function getToast() {
if (!toast) {
toast = new AbpToastService();
}
return toast;
}
abp.notify.success = function (message, title, options) { abp.notify.success = function (message, title, options) {
getToast().success(message, title, options); new AbpToastService().success(message, title, options);
}; };
abp.notify.info = function (message, title, options) { abp.notify.info = function (message, title, options) {
getToast().info(message, title, options); new AbpToastService().info(message, title, options);
}; };
abp.notify.warn = function (message, title, options) { abp.notify.warn = function (message, title, options) {
getToast().warning(message, title, options); new AbpToastService().warning(message, title, options);
}; };
abp.notify.error = function (message, title, options) { abp.notify.error = function (message, title, options) {
getToast().error(message, title, options); new AbpToastService().error(message, title, options);
}; };
})(); })();

24
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEfCoreNavigationHelper.cs

@ -31,6 +31,14 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
protected virtual void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry) protected virtual void EntityEntryTrackedOrStateChanged(EntityEntry entityEntry)
{ {
if (entityEntry.State is EntityState.Unchanged or EntityState.Modified)
{
foreach (var entry in EntityEntries.Values.Where(x => x.NavigationEntries.Any()))
{
entry.UpdateNavigationEntries();
}
}
if (entityEntry.State != EntityState.Unchanged) if (entityEntry.State != EntityState.Unchanged)
{ {
return; return;
@ -189,6 +197,22 @@ public class AbpEfCoreNavigationHelper : ITransientDependency
return navigationEntryProperty != null && navigationEntryProperty.IsModified; return navigationEntryProperty != null && navigationEntryProperty.IsModified;
} }
public virtual AbpNavigationEntry? GetNavigationEntry(EntityEntry entityEntry, int navigationEntryIndex)
{
var entryId = GetEntityEntryIdentity(entityEntry);
if (entryId == null)
{
return null;
}
if (!EntityEntries.TryGetValue(entryId, out var abpEntityEntry))
{
return null;
}
return abpEntityEntry.NavigationEntries.ElementAtOrDefault(navigationEntryIndex);
}
protected virtual string? GetEntityEntryIdentity(EntityEntry entityEntry) protected virtual string? GetEntityEntryIdentity(EntityEntry entityEntry)
{ {
if (entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1) if (entityEntry.Entity is IEntity entryEntity && entryEntity.GetKeys().Length == 1)

64
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ChangeTrackers/AbpEntityEntry.cs

@ -1,3 +1,4 @@
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -32,6 +33,49 @@ public class AbpEntityEntry
EntityEntry = entityEntry; EntityEntry = entityEntry;
NavigationEntries = EntityEntry.Navigations.Select(x => new AbpNavigationEntry(x, x.Metadata.Name)).ToList(); NavigationEntries = EntityEntry.Navigations.Select(x => new AbpNavigationEntry(x, x.Metadata.Name)).ToList();
} }
public void UpdateNavigationEntries()
{
foreach (var navigationEntry in NavigationEntries)
{
if (IsModified ||
EntityEntry.State == EntityState.Modified ||
navigationEntry.IsModified ||
navigationEntry.NavigationEntry.IsModified)
{
continue;
}
var navigation = EntityEntry.Navigations.FirstOrDefault(n => n.Metadata.Name == navigationEntry.Name);
var currentValue = AbpNavigationEntry.GetOriginalValue(navigation?.CurrentValue);
if (currentValue == null)
{
continue;
}
switch (navigationEntry.OriginalValue)
{
case null:
navigationEntry.OriginalValue = currentValue;
break;
case IEnumerable originalValueCollection when currentValue is IEnumerable currentValueCollection:
{
var existingList = originalValueCollection.Cast<object?>().ToList();
var newList = currentValueCollection.Cast<object?>().ToList();
if (newList.Count > existingList.Count)
{
navigationEntry.OriginalValue = currentValue;
}
break;
}
default:
navigationEntry.OriginalValue = currentValue;
break;
}
}
}
} }
public class AbpNavigationEntry public class AbpNavigationEntry
@ -42,9 +86,29 @@ public class AbpNavigationEntry
public bool IsModified { get; set; } public bool IsModified { get; set; }
public List<object>? OriginalValue { get; set; }
public object? CurrentValue => NavigationEntry.CurrentValue;
public AbpNavigationEntry(NavigationEntry navigationEntry, string name) public AbpNavigationEntry(NavigationEntry navigationEntry, string name)
{ {
NavigationEntry = navigationEntry; NavigationEntry = navigationEntry;
Name = name; Name = name;
OriginalValue = GetOriginalValue(navigationEntry.CurrentValue);
}
public static List<object>? GetOriginalValue(object? currentValue)
{
if (currentValue is null)
{
return null;
}
if (currentValue is IEnumerable enumerable)
{
return enumerable.Cast<object>().ToList();
}
return new List<object> { currentValue };
} }
} }

47
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -193,16 +194,20 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
} }
} }
if (Options.SaveEntityHistoryWhenNavigationChanges && AbpEfCoreNavigationHelper != null) if (AbpEfCoreNavigationHelper != null)
{ {
foreach (var (navigationEntry, index) in entityEntry.Navigations.Select((value, i) => ( value, i ))) foreach (var (navigationEntry, index) in entityEntry.Navigations.Select((value, i) => ( value, i )))
{ {
if (AbpEfCoreNavigationHelper.IsNavigationEntryModified(entityEntry, index)) if (AbpEfCoreNavigationHelper.IsNavigationEntryModified(entityEntry, index))
{ {
var abpNavigationEntry = AbpEfCoreNavigationHelper.GetNavigationEntry(entityEntry, index);
var isCollection = navigationEntry.Metadata.IsCollection;
propertyChanges.Add(new EntityPropertyChangeInfo propertyChanges.Add(new EntityPropertyChangeInfo
{ {
PropertyName = navigationEntry.Metadata.Name, PropertyName = navigationEntry.Metadata.Name,
PropertyTypeFullName = navigationEntry.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName! PropertyTypeFullName = navigationEntry.Metadata.ClrType.GetFirstGenericArgumentIfNullable().FullName!,
OriginalValue = GetNavigationPropertyValue(abpNavigationEntry?.OriginalValue, isCollection),
NewValue = GetNavigationPropertyValue(abpNavigationEntry?.CurrentValue, isCollection)
}); });
} }
} }
@ -211,6 +216,44 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency
return propertyChanges; return propertyChanges;
} }
protected virtual string? GetNavigationPropertyValue(object? entity, bool isCollection)
{
switch (entity)
{
case null:
return null;
case IEntity entryEntity:
var keys = entryEntity.GetKeys();
return keys.Length == 0 ? null : string.Join(", ",keys).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength);
case IEnumerable enumerable:
var keysList = new List<string>();
foreach (var item in enumerable)
{
var id = GetNavigationPropertyValue(item, false);
if (id != null)
{
keysList.Add(id);
}
}
if (keysList.Count == 0)
{
return null;
}
var serializedKeysEnumerable = keysList.Count == 1 && !isCollection
? keysList.First()
: JsonSerializer.Serialize(keysList);
return serializedKeysEnumerable.TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength);
default:
return null;
}
}
protected virtual bool IsCreated(EntityEntry entityEntry) protected virtual bool IsCreated(EntityEntry entityEntry)
{ {
return entityEntry.State == EntityState.Added; return entityEntry.State == EntityState.Added;

11
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Domain.Repositories.MongoDB; namespace Volo.Abp.Domain.Repositories.MongoDB;
@ -20,10 +20,13 @@ public interface IMongoDbRepository<TEntity> : IRepository<TEntity>
Task<IMongoCollection<TEntity>> GetCollectionAsync(CancellationToken cancellationToken = default); Task<IMongoCollection<TEntity>> GetCollectionAsync(CancellationToken cancellationToken = default);
[Obsolete("Use GetMongoQueryableAsync method.")] [Obsolete("Use GetQueryable method.")]
IMongoQueryable<TEntity> GetMongoQueryable(); IQueryable<TEntity> GetMongoQueryable();
Task<IMongoQueryable<TEntity>> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null); [Obsolete("Use GetQueryableAsync method.")]
Task<IQueryable<TEntity>> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null);
Task<IQueryable<TEntity>> GetQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null);
Task<IAggregateFluent<TEntity>> GetAggregateAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null); Task<IAggregateFluent<TEntity>> GetAggregateAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null);
} }

53
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -455,19 +455,19 @@ public class MongoDbRepository<TMongoDbContext, TEntity>
public async override Task<List<TEntity>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) public async override Task<List<TEntity>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)).ToListAsync(cancellationToken); return await (await GetQueryableAsync(cancellationToken)).ToListAsync(cancellationToken);
} }
public async override Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default) public async override Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)).Where(predicate).ToListAsync(cancellationToken); return await (await GetQueryableAsync(cancellationToken)).Where(predicate).ToListAsync(cancellationToken);
} }
public async override Task<long> GetCountAsync(CancellationToken cancellationToken = default) public async override Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)).LongCountAsync(cancellationToken); return await (await GetQueryableAsync(cancellationToken)).LongCountAsync(cancellationToken);
} }
public async override Task<List<TEntity>> GetPagedListAsync( public async override Task<List<TEntity>> GetPagedListAsync(
@ -479,10 +479,9 @@ public class MongoDbRepository<TMongoDbContext, TEntity>
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.OrderByIf<TEntity, IQueryable<TEntity>>(!sorting.IsNullOrWhiteSpace(), sorting) .OrderByIf<TEntity, IQueryable<TEntity>>(!sorting.IsNullOrWhiteSpace(), sorting)
.As<IMongoQueryable<TEntity>>() .PageBy<TEntity, IQueryable<TEntity>>(skipCount, maxResultCount)
.PageBy<TEntity, IMongoQueryable<TEntity>>(skipCount, maxResultCount)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
} }
@ -493,14 +492,14 @@ public class MongoDbRepository<TMongoDbContext, TEntity>
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
var entities = await (await GetMongoQueryableAsync(cancellationToken)) var entities = await (await GetQueryableAsync(cancellationToken))
.Where(predicate) .Where(predicate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
await DeleteManyAsync(entities, autoSave, cancellationToken); await DeleteManyAsync(entities, autoSave, cancellationToken);
} }
public override async Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) public async override Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
@ -527,12 +526,16 @@ public class MongoDbRepository<TMongoDbContext, TEntity>
[Obsolete("Use GetQueryableAsync method.")] [Obsolete("Use GetQueryableAsync method.")]
protected override IQueryable<TEntity> GetQueryable() protected override IQueryable<TEntity> GetQueryable()
{ {
return GetMongoQueryable(); return ApplyDataFilters(
SessionHandle != null
? Collection.AsQueryable(SessionHandle)
: Collection.AsQueryable()
);
} }
public async override Task<IQueryable<TEntity>> GetQueryableAsync() public async override Task<IQueryable<TEntity>> GetQueryableAsync()
{ {
return await GetMongoQueryableAsync(); return await GetQueryableAsync();
} }
public async override Task<TEntity?> FindAsync( public async override Task<TEntity?> FindAsync(
@ -542,34 +545,36 @@ public class MongoDbRepository<TMongoDbContext, TEntity>
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(predicate) .Where(predicate)
.SingleOrDefaultAsync(cancellationToken); .SingleOrDefaultAsync(cancellationToken);
} }
[Obsolete("Use GetMongoQueryableAsync method.")] [Obsolete("Use GetQueryableAsync method.")]
public virtual IMongoQueryable<TEntity> GetMongoQueryable() public virtual IQueryable<TEntity> GetMongoQueryable()
{ {
return ApplyDataFilters( return GetQueryable();
SessionHandle != null }
? Collection.AsQueryable(SessionHandle)
: Collection.AsQueryable() [Obsolete("Use GetQueryableAsync method.")]
); public virtual Task<IQueryable<TEntity>> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null)
{
return GetQueryableAsync<TEntity>(cancellationToken, options);
} }
public virtual Task<IMongoQueryable<TEntity>> GetMongoQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) public virtual async Task<IQueryable<TEntity>> GetQueryableAsync(CancellationToken cancellationToken = default, AggregateOptions? options = null)
{ {
return GetMongoQueryableAsync<TEntity>(cancellationToken, aggregateOptions); return await GetQueryableAsync<TEntity>(cancellationToken, options);
} }
protected virtual async Task<IMongoQueryable<TOtherEntity>> GetMongoQueryableAsync<TOtherEntity>(CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) protected virtual async Task<IQueryable<TOtherEntity>> GetQueryableAsync<TOtherEntity>(CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
var dbContext = await GetDbContextAsync(cancellationToken); var dbContext = await GetDbContextAsync(cancellationToken);
var collection = dbContext.Collection<TOtherEntity>(); var collection = dbContext.Collection<TOtherEntity>();
return ApplyDataFilters<IMongoQueryable<TOtherEntity>, TOtherEntity>( return ApplyDataFilters<IQueryable<TOtherEntity>, TOtherEntity>(
dbContext.SessionHandle != null dbContext.SessionHandle != null
? collection.AsQueryable(dbContext.SessionHandle, aggregateOptions) ? collection.AsQueryable(dbContext.SessionHandle, aggregateOptions)
: collection.AsQueryable(aggregateOptions) : collection.AsQueryable(aggregateOptions)
@ -810,7 +815,7 @@ public class MongoDbRepository<TMongoDbContext, TEntity, TKey>
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(x => x.Id!.Equals(id)) .Where(x => x.Id!.Equals(id))
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
} }
@ -827,7 +832,7 @@ public class MongoDbRepository<TMongoDbContext, TEntity, TKey>
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
var entities = await (await GetMongoQueryableAsync(cancellationToken)) var entities = await (await GetQueryableAsync(cancellationToken))
.Where(x => ids.Contains(x.Id)) .Where(x => ids.Contains(x.Id))
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);

15
framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs

@ -1,8 +1,8 @@
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.Domain.Repositories.MongoDB;
@ -36,19 +36,26 @@ public static class MongoDbCoreRepositoryExtensions
return repository.ToMongoDbRepository().GetCollectionAsync(cancellationToken); return repository.ToMongoDbRepository().GetCollectionAsync(cancellationToken);
} }
[Obsolete("Use GetMongoQueryableAsync method.")] [Obsolete("Use GetQueryableAsync method.")]
public static IMongoQueryable<TEntity> GetMongoQueryable<TEntity>(this IReadOnlyBasicRepository<TEntity> repository) public static IQueryable<TEntity> GetMongoQueryable<TEntity>(this IReadOnlyBasicRepository<TEntity> repository)
where TEntity : class, IEntity where TEntity : class, IEntity
{ {
return repository.ToMongoDbRepository().GetMongoQueryable(); return repository.ToMongoDbRepository().GetMongoQueryable();
} }
public static Task<IMongoQueryable<TEntity>> GetMongoQueryableAsync<TEntity>(this IReadOnlyBasicRepository<TEntity> repository, CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) [Obsolete("Use GetQueryableAsync method.")]
public static Task<IQueryable<TEntity>> GetMongoQueryableAsync<TEntity>(this IReadOnlyBasicRepository<TEntity> repository, CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null)
where TEntity : class, IEntity where TEntity : class, IEntity
{ {
return repository.ToMongoDbRepository().GetMongoQueryableAsync(cancellationToken, aggregateOptions); return repository.ToMongoDbRepository().GetMongoQueryableAsync(cancellationToken, aggregateOptions);
} }
public static Task<IQueryable<TEntity>> GetQueryableAsync<TEntity>(this IReadOnlyBasicRepository<TEntity> repository)
where TEntity : class, IEntity
{
return repository.ToMongoDbRepository().GetQueryableAsync();
}
public static Task<IAggregateFluent<TEntity>> GetAggregateAsync<TEntity>(this IReadOnlyBasicRepository<TEntity> repository, CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null) public static Task<IAggregateFluent<TEntity>> GetAggregateAsync<TEntity>(this IReadOnlyBasicRepository<TEntity> repository, CancellationToken cancellationToken = default, AggregateOptions? aggregateOptions = null)
where TEntity : class, IEntity where TEntity : class, IEntity
{ {

2
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbDateTimeSerializer.cs

@ -5,7 +5,7 @@ using MongoDB.Bson.Serialization.Serializers;
namespace Volo.Abp.MongoDB; namespace Volo.Abp.MongoDB;
public class AbpMongoDbDateTimeSerializer : DateTimeSerializer public class AbpMongoDbDateTimeSerializer : StructSerializerBase<DateTime>
{ {
protected DateTimeKind DateTimeKind { get; set; } protected DateTimeKind DateTimeKind { get; set; }
protected bool DisableDateTimeNormalization { get; set; } protected bool DisableDateTimeNormalization { get; set; }

5
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbModule.cs

@ -1,5 +1,8 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using Volo.Abp.Domain; using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -19,6 +22,8 @@ public class AbpMongoDbModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
BsonSerializer.TryRegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
context.Services.TryAddTransient( context.Services.TryAddTransient(
typeof(IMongoDbContextProvider<>), typeof(IMongoDbContextProvider<>),
typeof(UnitOfWorkMongoDbContextProvider<>) typeof(UnitOfWorkMongoDbContextProvider<>)

1
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventInbox.cs

@ -68,7 +68,6 @@ public class MongoDbContextEventInbox<TMongoDbContext> : IMongoDbContextEventInb
.WhereIf(transformedFilter != null, transformedFilter!) .WhereIf(transformedFilter != null, transformedFilter!)
.OrderBy(x => x.CreationTime) .OrderBy(x => x.CreationTime)
.Take(maxCount) .Take(maxCount)
.As<IMongoQueryable<IncomingEventRecord>>()
.ToListAsync(cancellationToken: cancellationToken); .ToListAsync(cancellationToken: cancellationToken);
return outgoingEventRecords return outgoingEventRecords

1
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventOutbox.cs

@ -56,7 +56,6 @@ public class MongoDbContextEventOutbox<TMongoDbContext> : IMongoDbContextEventOu
.WhereIf(transformedFilter != null, transformedFilter!) .WhereIf(transformedFilter != null, transformedFilter!)
.OrderBy(x => x.CreationTime) .OrderBy(x => x.CreationTime)
.Take(maxCount) .Take(maxCount)
.As<IMongoQueryable<OutgoingEventRecord>>()
.ToListAsync(cancellationToken: cancellationToken); .ToListAsync(cancellationToken: cancellationToken);
return outgoingEventRecords return outgoingEventRecords

141
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs

@ -6,9 +6,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Linq; using Volo.Abp.Linq;
using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.MongoDB; namespace Volo.Abp.MongoDB;
@ -16,344 +14,339 @@ public class MongoDbAsyncQueryableProvider : IAsyncQueryableProvider, ISingleton
{ {
public bool CanExecute<T>(IQueryable<T> queryable) public bool CanExecute<T>(IQueryable<T> queryable)
{ {
return ProxyHelper.UnProxy(queryable) is IMongoQueryable<T>; return queryable.Provider is IMongoQueryProvider;
}
protected virtual IMongoQueryable<T> GetMongoQueryable<T>(IQueryable<T> queryable)
{
return ProxyHelper.UnProxy(queryable).As<IMongoQueryable<T>>();
} }
public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default) public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default)
{ {
return Task.FromResult(GetMongoQueryable(queryable).Contains(item)); return Task.FromResult(queryable.Contains(item));
} }
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<bool> AnyAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AnyAsync(cancellationToken); return queryable.AnyAsync(cancellationToken);
} }
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AnyAsync(predicate, cancellationToken); return queryable.AnyAsync(predicate, cancellationToken);
} }
public Task<bool> AllAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<bool> AllAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return Task.FromResult(GetMongoQueryable(queryable).All(predicate)); return Task.FromResult(queryable.All(predicate));
} }
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).CountAsync(cancellationToken); return queryable.CountAsync(cancellationToken);
} }
public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).CountAsync(predicate, cancellationToken); return queryable.CountAsync(predicate, cancellationToken);
} }
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).LongCountAsync(cancellationToken); return queryable.LongCountAsync(cancellationToken);
} }
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).LongCountAsync(predicate, cancellationToken); return queryable.LongCountAsync(predicate, cancellationToken);
} }
public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).FirstAsync(cancellationToken); return queryable.FirstAsync(cancellationToken);
} }
public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).FirstAsync(predicate, cancellationToken); return queryable.FirstAsync(predicate, cancellationToken);
} }
public Task<T?> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T?> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).FirstOrDefaultAsync(cancellationToken)!; return queryable.FirstOrDefaultAsync(cancellationToken)!;
} }
public Task<T?> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, public Task<T?> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).FirstOrDefaultAsync(predicate, cancellationToken)!; return queryable.FirstOrDefaultAsync(predicate, cancellationToken)!;
} }
public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return Task.FromResult(GetMongoQueryable(queryable).Last()); return Task.FromResult(queryable.Last());
} }
public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return Task.FromResult(GetMongoQueryable(queryable).Last(predicate)); return Task.FromResult(queryable.Last(predicate));
} }
public Task<T?> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T?> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return Task.FromResult<T?>(GetMongoQueryable(queryable).LastOrDefault()); return Task.FromResult<T?>(queryable.LastOrDefault());
} }
public Task<T?> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, public Task<T?> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return Task.FromResult<T?>(GetMongoQueryable(queryable).LastOrDefault(predicate)); return Task.FromResult<T?>(queryable.LastOrDefault(predicate));
} }
public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SingleAsync(cancellationToken); return queryable.SingleAsync(cancellationToken);
} }
public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SingleAsync(predicate, cancellationToken); return queryable.SingleAsync(predicate, cancellationToken);
} }
public Task<T?> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T?> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SingleOrDefaultAsync(cancellationToken)!; return queryable.SingleOrDefaultAsync(cancellationToken)!;
} }
public Task<T?> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, public Task<T?> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SingleOrDefaultAsync(predicate, cancellationToken)!; return queryable.SingleOrDefaultAsync(predicate, cancellationToken)!;
} }
public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).MinAsync(cancellationToken); return queryable.MinAsync(cancellationToken);
} }
public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default) public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).MinAsync(selector, cancellationToken); return queryable.MinAsync(selector, cancellationToken);
} }
public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).MaxAsync(cancellationToken); return queryable.MaxAsync(cancellationToken);
} }
public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default) public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).MaxAsync(selector, cancellationToken); return queryable.MaxAsync(selector, cancellationToken);
} }
public Task<decimal> SumAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default) public Task<decimal> SumAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<decimal?> SumAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default) public Task<decimal?> SumAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default) public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default) public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<int> SumAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default) public Task<int> SumAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<int?> SumAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default) public Task<int?> SumAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default) public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default) public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<long> SumAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default) public Task<long> SumAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<long?> SumAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default) public Task<long?> SumAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default) public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default) public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<double> SumAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default) public Task<double> SumAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<double?> SumAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default) public Task<double?> SumAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default) public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default) public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<float> SumAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default) public Task<float> SumAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<float?> SumAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default) public Task<float?> SumAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(cancellationToken); return queryable.SumAsync(cancellationToken);
} }
public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default) public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default) public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken); return queryable.SumAsync(selector, cancellationToken);
} }
public Task<decimal> AverageAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default) public Task<decimal> AverageAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<decimal?> AverageAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default) public Task<decimal?> AverageAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default) public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default) public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<double> AverageAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default) public Task<double> AverageAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<double?> AverageAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default) public Task<double?> AverageAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default) public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default) public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<double> AverageAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default) public Task<double> AverageAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<double?> AverageAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default) public Task<double?> AverageAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default) public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default) public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<double> AverageAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default) public Task<double> AverageAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<double?> AverageAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default) public Task<double?> AverageAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default) public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default) public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<float> AverageAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default) public Task<float> AverageAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<float?> AverageAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default) public Task<float?> AverageAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(cancellationToken); return queryable.AverageAsync(cancellationToken);
} }
public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default) public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default) public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken); return queryable.AverageAsync(selector, cancellationToken);
} }
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return GetMongoQueryable(queryable).ToListAsync(cancellationToken); return queryable.ToListAsync(cancellationToken);
} }
public async Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) public async Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryable(queryable).ToListAsync(cancellationToken)).ToArray(); return (await queryable.ToListAsync(cancellationToken)).ToArray();
} }
} }

72
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.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.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
@ -512,7 +513,9 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName && x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 && x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToOne) && x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToOne) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName)); x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == null &&
x.EntityChanges[1].PropertyChanges[0].NewValue == entityId.ToString()));
AuditingStore.ClearReceivedCalls(); AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014 #pragma warning restore 4014
@ -539,10 +542,13 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName && x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 && x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToOne) && x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToOne) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName)); x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(AppEntityWithNavigationChildOneToOne).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == entityId.ToString() &&
x.EntityChanges[1].PropertyChanges[0].NewValue == null));
AuditingStore.ClearReceivedCalls(); AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014 #pragma warning restore 4014
var oneToManyId = "";
using (var scope = _auditingManager.BeginScope()) using (var scope = _auditingManager.BeginScope())
{ {
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
@ -561,6 +567,8 @@ public class Auditing_Tests : AbpAuditingTestBase
await repository.UpdateAsync(entity); await repository.UpdateAsync(entity);
await uow.CompleteAsync(); await uow.CompleteAsync();
await scope.SaveAsync(); await scope.SaveAsync();
oneToManyId = entity.OneToMany.First().Id.ToString();
} }
} }
@ -572,36 +580,80 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName && x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 && x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) && x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName)); x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == null &&
x.EntityChanges[1].PropertyChanges[0].NewValue == $"[\"{oneToManyId}\"]"));
AuditingStore.ClearReceivedCalls(); AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014 #pragma warning restore 4014
var newOneToManyId = "";
using (var scope = _auditingManager.BeginScope()) using (var scope = _auditingManager.BeginScope())
{ {
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
{ {
var entity = await repository.GetAsync(entityId); var entity = await repository.GetAsync(entityId);
entity.OneToMany = null; entity.OneToMany.Add(new AppEntityWithNavigationChildOneToMany
{
AppEntityWithNavigationId = entity.Id,
ChildName = "ChildName2"
});
await repository.UpdateAsync(entity); await repository.UpdateAsync(entity);
await uow.CompleteAsync(); await uow.CompleteAsync();
await scope.SaveAsync(); await scope.SaveAsync();
newOneToManyId = JsonSerializer.Serialize(entity.OneToMany.Select(x => x.Id).ToList());
} }
} }
#pragma warning disable 4014 #pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 && AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 2 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted && x.EntityChanges[0].ChangeType == EntityChangeType.Created &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName && x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated && x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName && x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 && x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) && x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName)); x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == $"[\"{oneToManyId}\"]" &&
x.EntityChanges[1].PropertyChanges[0].NewValue == newOneToManyId));
AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014
using (var scope = _auditingManager.BeginScope())
{
using (var uow = _unitOfWorkManager.Begin())
{
var entity = await repository.GetAsync(entityId);
newOneToManyId = JsonSerializer.Serialize(entity.OneToMany.Select(x => x.Id).ToList());
entity.OneToMany = null;
await repository.UpdateAsync(entity);
await uow.CompleteAsync();
await scope.SaveAsync();
}
}
#pragma warning disable 4014
AuditingStore.Received().SaveAsync(Arg.Is<AuditLogInfo>(x => x.EntityChanges.Count == 3 &&
x.EntityChanges[0].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[0].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[1].ChangeType == EntityChangeType.Deleted &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigationChildOneToMany).FullName &&
x.EntityChanges[2].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[2].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[2].PropertyChanges.Count == 1 &&
x.EntityChanges[2].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.OneToMany) &&
x.EntityChanges[2].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildOneToMany>).FullName &&
x.EntityChanges[2].PropertyChanges[0].OriginalValue == newOneToManyId &&
x.EntityChanges[2].PropertyChanges[0].NewValue == null));
AuditingStore.ClearReceivedCalls(); AuditingStore.ClearReceivedCalls();
#pragma warning restore 4014 #pragma warning restore 4014
var manyToManyId = "";
using (var scope = _auditingManager.BeginScope()) using (var scope = _auditingManager.BeginScope())
{ {
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
@ -619,6 +671,8 @@ public class Auditing_Tests : AbpAuditingTestBase
await repository.UpdateAsync(entity); await repository.UpdateAsync(entity);
await uow.CompleteAsync(); await uow.CompleteAsync();
await scope.SaveAsync(); await scope.SaveAsync();
manyToManyId = entity.ManyToMany.First().Id.ToString();
} }
} }
@ -630,7 +684,9 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName && x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigations).FullName &&
x.EntityChanges[1].PropertyChanges.Count == 1 && x.EntityChanges[1].PropertyChanges.Count == 1 &&
x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) && x.EntityChanges[1].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) &&
x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName)); x.EntityChanges[1].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName &&
x.EntityChanges[1].PropertyChanges[0].OriginalValue == null &&
x.EntityChanges[1].PropertyChanges[0].NewValue == $"[\"{manyToManyId}\"]"));
#pragma warning restore 4014 #pragma warning restore 4014
@ -655,6 +711,8 @@ public class Auditing_Tests : AbpAuditingTestBase
x.EntityChanges[0].PropertyChanges.Count == 1 && x.EntityChanges[0].PropertyChanges.Count == 1 &&
x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) && x.EntityChanges[0].PropertyChanges[0].PropertyName == nameof(AppEntityWithNavigations.ManyToMany) &&
x.EntityChanges[0].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName && x.EntityChanges[0].PropertyChanges[0].PropertyTypeFullName == typeof(List<AppEntityWithNavigationChildManyToMany>).FullName &&
x.EntityChanges[0].PropertyChanges[0].OriginalValue == $"[\"{manyToManyId}\"]" &&
x.EntityChanges[0].PropertyChanges[0].NewValue == null &&
x.EntityChanges[1].ChangeType == EntityChangeType.Updated && x.EntityChanges[1].ChangeType == EntityChangeType.Updated &&
x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigationChildManyToMany).FullName && x.EntityChanges[1].EntityTypeFullName == typeof(AppEntityWithNavigationChildManyToMany).FullName &&

8
framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj

@ -15,10 +15,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EphemeralMongo.Core" /> <PackageReference Include="MongoSandbox.Core" />
<PackageReference Include="EphemeralMongo6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" /> <PackageReference Include="MongoSandbox6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="EphemeralMongo6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> <PackageReference Include="MongoSandbox6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="EphemeralMongo6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" /> <PackageReference Include="MongoSandbox6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
<PackageReference Include="Microsoft.NET.Test.Sdk" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup> </ItemGroup>

5
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/MongoDbFixture.cs

@ -1,5 +1,5 @@
using System; using System;
using EphemeralMongo; using MongoSandbox;
namespace Volo.Abp.MongoDB; namespace Volo.Abp.MongoDB;
@ -11,7 +11,8 @@ public class MongoDbFixture : IDisposable
{ {
MongoDbRunner = MongoRunner.Run(new MongoRunnerOptions MongoDbRunner = MongoRunner.Run(new MongoRunnerOptions
{ {
UseSingleNodeReplicaSet = true UseSingleNodeReplicaSet = true,
ReplicaSetSetupTimeout = TimeSpan.FromSeconds(30)
}); });
} }

12
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs

@ -18,9 +18,9 @@ public class Repository_Basic_Tests : Repository_Basic_Tests<AbpMongoDbTestModul
public async Task ToMongoQueryable_Test() public async Task ToMongoQueryable_Test()
{ {
(await PersonRepository.GetQueryableAsync()).ShouldNotBeNull(); (await PersonRepository.GetQueryableAsync()).ShouldNotBeNull();
(await PersonRepository.GetQueryableAsync()).As<IMongoQueryable<Person>>().ShouldNotBeNull(); (await PersonRepository.GetQueryableAsync()).ShouldNotBeNull();
((IMongoQueryable<Person>)(await PersonRepository.GetQueryableAsync()).Where(p => p.Name == "Douglas")).ShouldNotBeNull(); ((IQueryable<Person>)(await PersonRepository.GetQueryableAsync()).Where(p => p.Name == "Douglas")).ShouldNotBeNull();
(await PersonRepository.GetQueryableAsync()).Where(p => p.Name == "Douglas").As<IMongoQueryable<Person>>().ShouldNotBeNull(); (await PersonRepository.GetQueryableAsync()).Where(p => p.Name == "Douglas").ShouldNotBeNull();
} }
[Fact] [Fact]
@ -69,9 +69,9 @@ public class Repository_Basic_Tests : Repository_Basic_Tests<AbpMongoDbTestModul
[Fact] [Fact]
public async Task Filter_Case_Insensitive() public async Task Filter_Case_Insensitive()
{ {
(await CityRepository.GetMongoQueryableAsync()).FirstOrDefault(c => c.Name == "ISTANBUL").ShouldBeNull(); (await CityRepository.GetQueryableAsync()).FirstOrDefault(c => c.Name == "ISTANBUL").ShouldBeNull();
(await CityRepository.GetMongoQueryableAsync()).FirstOrDefault(c => c.Name == "istanbul").ShouldBeNull(); (await CityRepository.GetQueryableAsync()).FirstOrDefault(c => c.Name == "istanbul").ShouldBeNull();
(await CityRepository.GetMongoQueryableAsync()).FirstOrDefault(c => c.Name == "Istanbul").ShouldNotBeNull(); (await CityRepository.GetQueryableAsync()).FirstOrDefault(c => c.Name == "Istanbul").ShouldNotBeNull();
(await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "douglas").ShouldNotBeNull(); (await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "douglas").ShouldNotBeNull();
(await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "DOUGLAS").ShouldNotBeNull(); (await PersonRepository.GetQueryableAsync()).FirstOrDefault(p => p.Name == "DOUGLAS").ShouldNotBeNull();

1
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;

101
modules/account/src/Volo.Abp.Account.HttpApi/Volo.Abp.Account.HttpApi.abppkg.analyze.json

@ -68,107 +68,6 @@
"contentType": "abpModule", "contentType": "abpModule",
"name": "AbpAccountHttpApiModule", "name": "AbpAccountHttpApiModule",
"summary": null "summary": null
},
{
"apis": [
{
"path": "api/account/register",
"method": "POST",
"groupName": "Account",
"responseType": "Volo.Abp.Identity.IdentityUserDto",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "input",
"type": "RegisterDto"
}
]
},
{
"path": "api/account/send-password-reset-code",
"method": "POST",
"groupName": "Account",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "input",
"type": "SendPasswordResetCodeDto"
}
]
},
{
"path": "api/account/verify-password-reset-token",
"method": "POST",
"groupName": "Account",
"responseType": "System.Boolean",
"responseTypeAsJson": "true",
"parameterDescriptions": [
{
"name": "input",
"type": "VerifyPasswordResetTokenInput"
}
]
},
{
"path": "api/account/reset-password",
"method": "POST",
"groupName": "Account",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "input",
"type": "ResetPasswordDto"
}
]
},
{
"path": "api/account/dynamic-claims/refresh",
"method": "POST",
"groupName": "DynamicClaims",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": []
},
{
"path": "api/account/my-profile",
"method": "GET",
"groupName": "Profile",
"responseType": "Volo.Abp.Account.ProfileDto",
"responseTypeAsJson": "",
"parameterDescriptions": []
},
{
"path": "api/account/my-profile",
"method": "PUT",
"groupName": "Profile",
"responseType": "Volo.Abp.Account.ProfileDto",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "input",
"type": "UpdateProfileDto"
}
]
},
{
"path": "api/account/my-profile/change-password",
"method": "POST",
"groupName": "Profile",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "input",
"type": "ChangePasswordInput"
}
]
}
],
"contentType": "httpApi",
"name": "Defined Http Apis",
"summary": null
} }
] ]
} }

41
modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.abppkg.analyze.json

@ -79,47 +79,6 @@
"name": "AbpAccountWebModule", "name": "AbpAccountWebModule",
"summary": null "summary": null
}, },
{
"apis": [
{
"path": "api/account/login",
"method": "POST",
"groupName": "Account",
"responseType": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.AbpLoginResult",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "login",
"type": "UserLoginInfo"
}
]
},
{
"path": "api/account/logout",
"method": "GET",
"groupName": "Account",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": []
},
{
"path": "api/account/check-password",
"method": "POST",
"groupName": "Account",
"responseType": "Volo.Abp.Account.Web.Areas.Account.Controllers.Models.AbpLoginResult",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "login",
"type": "UserLoginInfo"
}
]
}
],
"contentType": "httpApi",
"name": "Defined Http Apis",
"summary": null
},
{ {
"namespace": "Volo.Abp.Account.Web.Pages.Account", "namespace": "Volo.Abp.Account.Web.Pages.Account",
"contentType": "webPage", "contentType": "webPage",

2
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json

@ -48,7 +48,7 @@
"ChangeType": "Change type", "ChangeType": "Change type",
"ChangeTime": "Time", "ChangeTime": "Time",
"NewValue": "New value", "NewValue": "New value",
"OriginalValue": "Original value", "OriginalValue": "Old value",
"PropertyName": "Property name", "PropertyName": "Property name",
"PropertyTypeFullName": "Property Type Full Name", "PropertyTypeFullName": "Property Type Full Name",
"Yes": "Yes", "Yes": "Yes",

39
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter.cs

@ -0,0 +1,39 @@
using System;
using System.Text.RegularExpressions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AuditLogging;
public class AuditLogEntityTypeFullNameConverter : ITransientDependency
{
public virtual string Convert(string typeFullName)
{
var genericType = Regex.Match(typeFullName, @"(.+?)`1\[\[");
if (!genericType.Success)
{
return ReplaceGenericSymbol(typeFullName);
}
var type = Regex.Match(typeFullName, @"`1\[\[(.+?), ");
if (!type.Success)
{
return typeFullName;
}
if (type.Groups[1].Value.Contains("System.Nullable`1[["))
{
return genericType.Groups[1].Value + "<" + type.Groups[1].Value.Replace("System.Nullable`1[[", "") + "?>";
}
return genericType.Groups[1].Value.Contains("System.Nullable")
? type.Groups[1].Value + "?"
: genericType.Groups[1].Value + "<" + ReplaceGenericSymbol(type.Groups[1].Value) + ">";
}
protected virtual string ReplaceGenericSymbol(string typeFullName)
{
return typeFullName.Contains("`1+")
? typeFullName.Substring(0, typeFullName.IndexOf("[[", StringComparison.Ordinal)).Replace("`1+", ".")
: typeFullName;
}
}

18
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogInfoToAuditLogConverter.cs

@ -19,12 +19,19 @@ public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter,
protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; } protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
protected IJsonSerializer JsonSerializer { get; } protected IJsonSerializer JsonSerializer { get; }
protected AbpExceptionHandlingOptions ExceptionHandlingOptions { get; } protected AbpExceptionHandlingOptions ExceptionHandlingOptions { get; }
protected AuditLogEntityTypeFullNameConverter AuditLogEntityTypeFullNameConverter { get; }
public AuditLogInfoToAuditLogConverter(IGuidGenerator guidGenerator, IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, IJsonSerializer jsonSerializer, IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions) public AuditLogInfoToAuditLogConverter(
IGuidGenerator guidGenerator,
IExceptionToErrorInfoConverter exceptionToErrorInfoConverter,
IJsonSerializer jsonSerializer,
IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions,
AuditLogEntityTypeFullNameConverter auditLogEntityTypeFullNameConverter)
{ {
GuidGenerator = guidGenerator; GuidGenerator = guidGenerator;
ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter; ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
AuditLogEntityTypeFullNameConverter = auditLogEntityTypeFullNameConverter;
ExceptionHandlingOptions = exceptionHandlingOptions.Value; ExceptionHandlingOptions = exceptionHandlingOptions.Value;
} }
@ -41,6 +48,15 @@ public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter,
} }
} }
foreach (var entityChange in auditLogInfo.EntityChanges ?? Enumerable.Empty<EntityChangeInfo>())
{
entityChange.EntityTypeFullName = AuditLogEntityTypeFullNameConverter.Convert(entityChange.EntityTypeFullName);
foreach (var propertyChange in entityChange.PropertyChanges ?? Enumerable.Empty<EntityPropertyChangeInfo>())
{
propertyChange.PropertyTypeFullName = AuditLogEntityTypeFullNameConverter.Convert(propertyChange.PropertyTypeFullName);
}
}
var entityChanges = auditLogInfo var entityChanges = auditLogInfo
.EntityChanges? .EntityChanges?
.Select(entityChangeInfo => new EntityChange(GuidGenerator, auditLogId, entityChangeInfo, tenantId: auditLogInfo.TenantId)) .Select(entityChangeInfo => new EntityChange(GuidGenerator, auditLogId, entityChangeInfo, tenantId: auditLogInfo.TenantId))

9
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.abppkg.analyze.json

@ -67,7 +67,14 @@
{ {
"namespace": "Volo.Abp.AuditLogging.EntityFrameworkCore", "namespace": "Volo.Abp.AuditLogging.EntityFrameworkCore",
"connectionStringName": "AbpAuditLogging", "connectionStringName": "AbpAuditLogging",
"databaseTables": [], "databaseTables": [
{
"entityFullName": "Volo.Abp.AuditLogging.AuditLog",
"contentType": "databaseTable",
"name": "AuditLogs",
"summary": null
}
],
"replacedDbContexts": [], "replacedDbContexts": [],
"modelBuilderExtensionMethods": [ "modelBuilderExtensionMethods": [
{ {

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

@ -64,8 +64,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
return await query return await query
.OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(AuditLog.ExecutionTime) + " DESC") : sorting) .OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(AuditLog.ExecutionTime) + " DESC") : sorting)
.As<IMongoQueryable<AuditLog>>() .PageBy(skipCount, maxResultCount)
.PageBy<AuditLog, IMongoQueryable<AuditLog>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }
@ -104,8 +103,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
cancellationToken: cancellationToken cancellationToken: cancellationToken
); );
var count = await query.As<IMongoQueryable<AuditLog>>() var count = await query.LongCountAsync(GetCancellationToken(cancellationToken));
.LongCountAsync(GetCancellationToken(cancellationToken));
return count; return count;
} }
@ -128,7 +126,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
bool includeDetails = false, bool includeDetails = false,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync(cancellationToken)) return (await GetQueryableAsync(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 != "")
@ -151,7 +149,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
DateTime endDate, DateTime endDate,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var result = await (await GetMongoQueryableAsync(cancellationToken)) var result = await (await GetQueryableAsync(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 {
@ -169,7 +167,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
Guid entityChangeId, Guid entityChangeId,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var entityChange = (await (await GetMongoQueryableAsync(cancellationToken)) var entityChange = (await (await GetQueryableAsync(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(GetCancellationToken(cancellationToken))).EntityChanges.FirstOrDefault(x => x.Id == entityChangeId); .FirstAsync(GetCancellationToken(cancellationToken))).EntityChanges.FirstOrDefault(x => x.Id == entityChangeId);
@ -199,8 +197,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
return await query return await query
.OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(EntityChange.ChangeTime) + " DESC") : sorting) .OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(EntityChange.ChangeTime) + " DESC") : sorting)
.As<IMongoQueryable<EntityChange>>() .PageBy(skipCount, maxResultCount)
.PageBy<EntityChange, IMongoQueryable<EntityChange>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }
@ -215,7 +212,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
{ {
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, cancellationToken); 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.LongCountAsync(GetCancellationToken(cancellationToken));
return count; return count;
} }
@ -224,7 +221,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
Guid entityChangeId, Guid entityChangeId,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var auditLog = await (await GetMongoQueryableAsync(cancellationToken)) var auditLog = await (await GetQueryableAsync(cancellationToken))
.Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)) .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId))
.FirstAsync(GetCancellationToken(cancellationToken)); .FirstAsync(GetCancellationToken(cancellationToken));
@ -240,9 +237,8 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
string entityTypeFullName, string entityTypeFullName,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var auditLogs = await (await GetMongoQueryableAsync(cancellationToken)) var auditLogs = await (await GetQueryableAsync(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>>()
.OrderByDescending(x => x.ExecutionTime) .OrderByDescending(x => x.ExecutionTime)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
@ -263,7 +259,7 @@ public class MongoAuditLogRepository : MongoDbRepository<IAuditLoggingMongoDbCon
string entityTypeFullName = null, string entityTypeFullName = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync(cancellationToken)) return (await GetQueryableAsync(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)

6
modules/audit-logging/test/Volo.Abp.AuditLogging.EntityFrameworkCore.Tests/Volo/Abp/AuditLogging/EntityFrameworkCore/AuditLogEntityTypeFullNameConverter_Tests.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AuditLogging.EntityFrameworkCore;
public class AuditLogEntityTypeFullNameConverter_Tests : AuditLogEntityTypeFullNameConverter_Tests<AbpAuditLoggingEntityFrameworkCoreTestModule>
{
}

8
modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.csproj

@ -14,10 +14,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="EphemeralMongo.Core" /> <PackageReference Include="MongoSandbox.Core" />
<PackageReference Include="EphemeralMongo6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" /> <PackageReference Include="MongoSandbox6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="EphemeralMongo6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> <PackageReference Include="MongoSandbox6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="EphemeralMongo6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" /> <PackageReference Include="MongoSandbox6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
</ItemGroup> </ItemGroup>
</Project> </Project>

9
modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/AuditLogEntityTypeFullNameConverter_Tests.cs

@ -0,0 +1,9 @@
using Xunit;
namespace Volo.Abp.AuditLogging.MongoDB;
[Collection(MongoTestCollection.Name)]
public class AuditLogEntityTypeFullNameConverter_Tests : AuditLogEntityTypeFullNameConverter_Tests<AbpAuditLoggingMongoDbTestModule>
{
}

2
modules/audit-logging/test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo/Abp/AuditLogging/MongoDB/MongoDbFixture.cs

@ -1,5 +1,5 @@
using System; using System;
using EphemeralMongo; using MongoSandbox;
namespace Volo.Abp.AuditLogging.MongoDB; namespace Volo.Abp.AuditLogging.MongoDB;

46
modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditLogEntityTypeFullNameConverter_Tests.cs

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.AuditLogging;
public abstract class AuditLogEntityTypeFullNameConverter_Tests<TStartupModule> : AuditLoggingTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly AuditLogEntityTypeFullNameConverter _typeFullNameConverter;
protected AuditLogEntityTypeFullNameConverter_Tests()
{
_typeFullNameConverter = GetRequiredService<AuditLogEntityTypeFullNameConverter>();
}
[Fact]
public void AuditLogEntityTypeFullNameConverter_Test()
{
_typeFullNameConverter.Convert("MyType").ShouldBe("MyType");
_typeFullNameConverter.Convert(typeof(string).FullName!).ShouldBe("System.String");
_typeFullNameConverter.Convert(typeof(Guid).FullName!).ShouldBe("System.Guid");
_typeFullNameConverter.Convert(typeof(Guid?).FullName!).ShouldBe("System.Guid?");
_typeFullNameConverter.Convert(typeof(int).FullName!).ShouldBe("System.Int32");
_typeFullNameConverter.Convert(typeof(long?).FullName!).ShouldBe("System.Int64?");
_typeFullNameConverter.Convert(typeof(MyClass).FullName!).ShouldBe("Volo.Abp.AuditLogging.AuditLogEntityTypeFullNameConverter_Tests.MyClass");
_typeFullNameConverter.Convert(typeof(ICollection<string>).FullName!).ShouldBe($"System.Collections.Generic.ICollection<System.String>");
_typeFullNameConverter.Convert(typeof(Collection<int>).FullName!).ShouldBe($"System.Collections.ObjectModel.Collection<System.Int32>");
_typeFullNameConverter.Convert(typeof(List<Guid>).FullName!).ShouldBe($"System.Collections.Generic.List<System.Guid>");
_typeFullNameConverter.Convert(typeof(List<MyClass>).FullName!).ShouldBe($"System.Collections.Generic.List<Volo.Abp.AuditLogging.AuditLogEntityTypeFullNameConverter_Tests.MyClass>");
_typeFullNameConverter.Convert(typeof(ICollection<long?>).FullName!).ShouldBe($"System.Collections.Generic.ICollection<System.Int64?>");
_typeFullNameConverter.Convert(typeof(Collection<int?>).FullName!).ShouldBe($"System.Collections.ObjectModel.Collection<System.Int32?>");
_typeFullNameConverter.Convert(typeof(List<Guid?>).FullName!).ShouldBe($"System.Collections.Generic.List<System.Guid?>");
}
public class MyClass
{
}
}

9
modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.abppkg.analyze.json

@ -67,7 +67,14 @@
{ {
"namespace": "Volo.Abp.BackgroundJobs.EntityFrameworkCore", "namespace": "Volo.Abp.BackgroundJobs.EntityFrameworkCore",
"connectionStringName": "AbpBackgroundJobs", "connectionStringName": "AbpBackgroundJobs",
"databaseTables": [], "databaseTables": [
{
"entityFullName": "Volo.Abp.BackgroundJobs.BackgroundJobRecord",
"contentType": "databaseTable",
"name": "BackgroundJobs",
"summary": null
}
],
"replacedDbContexts": [], "replacedDbContexts": [],
"modelBuilderExtensionMethods": [ "modelBuilderExtensionMethods": [
{ {

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

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.Domain.Repositories.MongoDB;
@ -29,10 +30,10 @@ public class MongoBackgroundJobRepository : MongoDbRepository<IBackgroundJobsMon
return await (await GetWaitingListQuery(maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken)); return await (await GetWaitingListQuery(maxResultCount)).ToListAsync(GetCancellationToken(cancellationToken));
} }
protected virtual async Task<IMongoQueryable<BackgroundJobRecord>> GetWaitingListQuery(int maxResultCount, CancellationToken cancellationToken = default) protected virtual async Task<IQueryable<BackgroundJobRecord>> GetWaitingListQuery(int maxResultCount, CancellationToken cancellationToken = default)
{ {
var now = Clock.Now; var now = Clock.Now;
return (await GetMongoQueryableAsync(cancellationToken)) return (await GetQueryableAsync(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)

8
modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo.Abp.BackgroundJobs.MongoDB.Tests.csproj

@ -14,10 +14,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="EphemeralMongo.Core" /> <PackageReference Include="MongoSandbox.Core" />
<PackageReference Include="EphemeralMongo6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" /> <PackageReference Include="MongoSandbox6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="EphemeralMongo6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> <PackageReference Include="MongoSandbox6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="EphemeralMongo6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" /> <PackageReference Include="MongoSandbox6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
</ItemGroup> </ItemGroup>
</Project> </Project>

2
modules/background-jobs/test/Volo.Abp.BackgroundJobs.MongoDB.Tests/Volo/Abp/BackgroundJobs/MongoDB/MongoDbFixture.cs

@ -1,5 +1,5 @@
using System; using System;
using EphemeralMongo; using MongoSandbox;
namespace Volo.Abp.BackgroundJobs.MongoDB; namespace Volo.Abp.BackgroundJobs.MongoDB;

15
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo.Abp.BlobStoring.Database.EntityFrameworkCore.abppkg.analyze.json

@ -67,7 +67,20 @@
{ {
"namespace": "Volo.Abp.BlobStoring.Database.EntityFrameworkCore", "namespace": "Volo.Abp.BlobStoring.Database.EntityFrameworkCore",
"connectionStringName": "AbpBlobStoring", "connectionStringName": "AbpBlobStoring",
"databaseTables": [], "databaseTables": [
{
"entityFullName": "Volo.Abp.BlobStoring.Database.DatabaseBlobContainer",
"contentType": "databaseTable",
"name": "BlobContainers",
"summary": null
},
{
"entityFullName": "Volo.Abp.BlobStoring.Database.DatabaseBlob",
"contentType": "databaseTable",
"name": "Blobs",
"summary": null
}
],
"replacedDbContexts": [], "replacedDbContexts": [],
"modelBuilderExtensionMethods": [ "modelBuilderExtensionMethods": [
{ {

4
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/MongoDbDatabaseBlobRepository.cs

@ -17,7 +17,7 @@ public class MongoDbDatabaseBlobRepository : MongoDbRepository<IBlobStoringMongo
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.FirstOrDefaultAsync( .FirstOrDefaultAsync(
x => x.ContainerId == containerId && x.Name == name, x => x.ContainerId == containerId && x.Name == name,
cancellationToken cancellationToken
@ -28,7 +28,7 @@ public class MongoDbDatabaseBlobRepository : MongoDbRepository<IBlobStoringMongo
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.AnyAsync( .AnyAsync(
x => x.ContainerId == containerId && x.Name == name, x => x.ContainerId == containerId && x.Name == name,
cancellationToken cancellationToken

2
modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/MongoDB/MongoDbFixture.cs

@ -1,5 +1,5 @@
using System; using System;
using EphemeralMongo; using MongoSandbox;
namespace Volo.Abp.BlobStoring.Database.MongoDB; namespace Volo.Abp.BlobStoring.Database.MongoDB;

8
modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.MongoDB.Tests/Volo.Abp.BlobStoring.Database.MongoDB.Tests.csproj

@ -7,10 +7,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="EphemeralMongo.Core" /> <PackageReference Include="MongoSandbox.Core" />
<PackageReference Include="EphemeralMongo6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" /> <PackageReference Include="MongoSandbox6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="EphemeralMongo6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> <PackageReference Include="MongoSandbox6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="EphemeralMongo6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" /> <PackageReference Include="MongoSandbox6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
<ProjectReference Include="..\..\src\Volo.Abp.BlobStoring.Database.MongoDB\Volo.Abp.BlobStoring.Database.MongoDB.csproj" /> <ProjectReference Include="..\..\src\Volo.Abp.BlobStoring.Database.MongoDB\Volo.Abp.BlobStoring.Database.MongoDB.csproj" />
<ProjectReference Include="..\Volo.Abp.BlobStoring.Database.TestBase\Volo.Abp.BlobStoring.Database.TestBase.csproj" /> <ProjectReference Include="..\Volo.Abp.BlobStoring.Database.TestBase\Volo.Abp.BlobStoring.Database.TestBase.csproj" />
</ItemGroup> </ItemGroup>

2
modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.abppkg.analyze.json

@ -1,6 +1,6 @@
{ {
"name": "Volo.BloggingTestApp", "name": "Volo.BloggingTestApp",
"hash": "faf8c09c571a52e961d15c9dd9c7d7ac", "hash": "",
"contents": [ "contents": [
{ {
"namespace": "Volo.BloggingTestApp", "namespace": "Volo.BloggingTestApp",

84
modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.analyze.json

@ -63,90 +63,6 @@
"contentType": "abpModule", "contentType": "abpModule",
"name": "BloggingAdminHttpApiModule", "name": "BloggingAdminHttpApiModule",
"summary": null "summary": null
},
{
"apis": [
{
"path": "api/blogging/blogs/admin",
"method": "GET",
"groupName": "BlogManagement",
"responseType": "Volo.Abp.Application.Dtos.ListResultDto`1[Volo.Blogging.Blogs.Dtos.BlogDto]",
"responseTypeAsJson": "{\r\n \"items\": [\r\n {\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ]\r\n}",
"parameterDescriptions": []
},
{
"path": "api/blogging/blogs/admin/{id}",
"method": "GET",
"groupName": "BlogManagement",
"responseType": "Volo.Blogging.Blogs.Dtos.BlogDto",
"responseTypeAsJson": "{\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
},
{
"path": "api/blogging/blogs/admin",
"method": "POST",
"groupName": "BlogManagement",
"responseType": "Volo.Blogging.Blogs.Dtos.BlogDto",
"responseTypeAsJson": "{\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "input",
"type": "CreateBlogDto"
}
]
},
{
"path": "api/blogging/blogs/admin/{id}",
"method": "PUT",
"groupName": "BlogManagement",
"responseType": "Volo.Blogging.Blogs.Dtos.BlogDto",
"responseTypeAsJson": "{\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
},
{
"name": "input",
"type": "UpdateBlogDto"
}
]
},
{
"path": "api/blogging/blogs/admin/{id}",
"method": "DELETE",
"groupName": "BlogManagement",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
},
{
"path": "api/blogging/blogs/admin/clear-cache/{id}",
"method": "GET",
"groupName": "BlogManagement",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
}
],
"contentType": "httpApi",
"name": "Defined Http Apis",
"summary": null
} }
] ]
} }

77
modules/blogging/src/Volo.Blogging.Domain/Volo.Blogging.Domain.abppkg.analyze.json

@ -1717,6 +1717,83 @@
"contentType": "repositoryInterface", "contentType": "repositoryInterface",
"name": "IBlogRepository", "name": "IBlogRepository",
"summary": null "summary": null
},
{
"eventHandlerType": "Distributed",
"namespace": "Volo.Blogging.Users",
"subscribedEvents": [
{
"underlyingType": {
"name": "UserEto",
"namespace": "Volo.Abp.Users",
"declaringAssemblyName": "Volo.Abp.Users.Abstractions",
"fullName": "Volo.Abp.Users.UserEto"
},
"name": "EntityUpdatedEto`1",
"namespace": "Volo.Abp.Domain.Entities.Events.Distributed",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain.Shared",
"fullName": "Volo.Abp.Domain.Entities.Events.Distributed.EntityUpdatedEto`1"
}
],
"implementingInterfaces": [
{
"name": "IDistributedEventHandler<EntityUpdatedEto`1>",
"namespace": "Volo.Abp.EventBus.Distributed",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.Distributed.IDistributedEventHandler<EntityUpdatedEto`1>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "BlogUserSynchronizer",
"summary": null
},
{
"eventHandlerType": "Local",
"namespace": "Volo.Blogging.Posts",
"subscribedEvents": [
{
"underlyingType": null,
"name": "PostChangedEvent",
"namespace": "Volo.Blogging.Posts",
"declaringAssemblyName": "Volo.Blogging.Domain",
"fullName": "Volo.Blogging.Posts.PostChangedEvent"
}
],
"implementingInterfaces": [
{
"name": "ILocalEventHandler<PostChangedEvent>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<PostChangedEvent>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "PostCacheInvalidator",
"summary": null
} }
] ]
} }

39
modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.abppkg.analyze.json

@ -67,7 +67,44 @@
{ {
"namespace": "Volo.Blogging.EntityFrameworkCore", "namespace": "Volo.Blogging.EntityFrameworkCore",
"connectionStringName": "Blogging", "connectionStringName": "Blogging",
"databaseTables": [], "databaseTables": [
{
"entityFullName": "Volo.Blogging.Users.BlogUser",
"contentType": "databaseTable",
"name": "Users",
"summary": null
},
{
"entityFullName": "Volo.Blogging.Blogs.Blog",
"contentType": "databaseTable",
"name": "Blogs",
"summary": null
},
{
"entityFullName": "Volo.Blogging.Posts.Post",
"contentType": "databaseTable",
"name": "Posts",
"summary": null
},
{
"entityFullName": "Volo.Blogging.Tagging.Tag",
"contentType": "databaseTable",
"name": "Tags",
"summary": null
},
{
"entityFullName": "Volo.Blogging.Posts.PostTag",
"contentType": "databaseTable",
"name": "PostTags",
"summary": null
},
{
"entityFullName": "Volo.Blogging.Comments.Comment",
"contentType": "databaseTable",
"name": "Comments",
"summary": null
}
],
"replacedDbContexts": [], "replacedDbContexts": [],
"modelBuilderExtensionMethods": [ "modelBuilderExtensionMethods": [
{ {

294
modules/blogging/src/Volo.Blogging.HttpApi/Volo.Blogging.HttpApi.abppkg.analyze.json

@ -63,300 +63,6 @@
"contentType": "abpModule", "contentType": "abpModule",
"name": "BloggingHttpApiModule", "name": "BloggingHttpApiModule",
"summary": null "summary": null
},
{
"apis": [
{
"path": "api/blogging/files/{name}",
"method": "GET",
"groupName": "BlogFiles",
"responseType": "Volo.Blogging.Files.RawFileDto",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "name",
"type": "String"
}
]
},
{
"path": "api/blogging/files/www/{name}",
"method": "GET",
"groupName": "BlogFiles",
"responseType": "Volo.Abp.Content.IRemoteStreamContent",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "name",
"type": "String"
}
]
},
{
"path": "api/blogging/files/images/upload",
"method": "POST",
"groupName": "BlogFiles",
"responseType": "Volo.Blogging.Files.FileUploadOutputDto",
"responseTypeAsJson": "{\r\n \"name\": \"string\",\r\n \"webUrl\": \"string\"\r\n}",
"parameterDescriptions": [
{
"name": "File",
"type": "IRemoteStreamContent"
},
{
"name": "Name",
"type": "String"
}
]
},
{
"path": "api/blogging/blogs",
"method": "GET",
"groupName": "Blogs",
"responseType": "Volo.Abp.Application.Dtos.ListResultDto`1[Volo.Blogging.Blogs.Dtos.BlogDto]",
"responseTypeAsJson": "{\r\n \"items\": [\r\n {\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ]\r\n}",
"parameterDescriptions": []
},
{
"path": "api/blogging/blogs/by-shortname/{shortName}",
"method": "GET",
"groupName": "Blogs",
"responseType": "Volo.Blogging.Blogs.Dtos.BlogDto",
"responseTypeAsJson": "{\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "shortName",
"type": "String"
}
]
},
{
"path": "api/blogging/blogs/{id}",
"method": "GET",
"groupName": "Blogs",
"responseType": "Volo.Blogging.Blogs.Dtos.BlogDto",
"responseTypeAsJson": "{\r\n \"name\": \"string\",\r\n \"shortName\": \"string\",\r\n \"description\": \"string\",\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
},
{
"path": "api/blogging/comments/hierarchical/{postId}",
"method": "GET",
"groupName": "Comments",
"responseType": "System.Collections.Generic.List`1[Volo.Blogging.Comments.Dtos.CommentWithRepliesDto]",
"responseTypeAsJson": "[\r\n {\r\n \"comment\": {\r\n \"repliedCommentId\": null,\r\n \"text\": \"string\",\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"replies\": [\r\n {\r\n \"repliedCommentId\": null,\r\n \"text\": \"string\",\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ]\r\n }\r\n]",
"parameterDescriptions": [
{
"name": "postId",
"type": "Guid"
}
]
},
{
"path": "api/blogging/comments",
"method": "POST",
"groupName": "Comments",
"responseType": "Volo.Blogging.Comments.Dtos.CommentWithDetailsDto",
"responseTypeAsJson": "{\r\n \"repliedCommentId\": null,\r\n \"text\": \"string\",\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "input",
"type": "CreateCommentDto"
}
]
},
{
"path": "api/blogging/comments/{id}",
"method": "PUT",
"groupName": "Comments",
"responseType": "Volo.Blogging.Comments.Dtos.CommentWithDetailsDto",
"responseTypeAsJson": "{\r\n \"repliedCommentId\": null,\r\n \"text\": \"string\",\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
},
{
"name": "input",
"type": "UpdateCommentDto"
}
]
},
{
"path": "api/blogging/comments/{id}",
"method": "DELETE",
"groupName": "Comments",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
},
{
"path": "api/blogging/posts/{blogId}/all",
"method": "GET",
"groupName": "Posts",
"responseType": "Volo.Abp.Application.Dtos.ListResultDto`1[Volo.Blogging.Posts.PostWithDetailsDto]",
"responseTypeAsJson": "{\r\n \"items\": [\r\n {\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ]\r\n}",
"parameterDescriptions": [
{
"name": "blogId",
"type": "Guid"
},
{
"name": "tagName",
"type": "String"
}
]
},
{
"path": "api/blogging/posts/{blogId}/all/by-time",
"method": "GET",
"groupName": "Posts",
"responseType": "Volo.Abp.Application.Dtos.ListResultDto`1[Volo.Blogging.Posts.PostWithDetailsDto]",
"responseTypeAsJson": "{\r\n \"items\": [\r\n {\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ]\r\n}",
"parameterDescriptions": [
{
"name": "blogId",
"type": "Guid"
}
]
},
{
"path": "api/blogging/posts/read",
"method": "GET",
"groupName": "Posts",
"responseType": "Volo.Blogging.Posts.PostWithDetailsDto",
"responseTypeAsJson": "{\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "Url",
"type": "String"
},
{
"name": "BlogId",
"type": "Guid"
}
]
},
{
"path": "api/blogging/posts/{id}",
"method": "GET",
"groupName": "Posts",
"responseType": "Volo.Blogging.Posts.PostWithDetailsDto",
"responseTypeAsJson": "{\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
},
{
"path": "api/blogging/posts",
"method": "POST",
"groupName": "Posts",
"responseType": "Volo.Blogging.Posts.PostWithDetailsDto",
"responseTypeAsJson": "{\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "input",
"type": "CreatePostDto"
}
]
},
{
"path": "api/blogging/posts/{id}",
"method": "PUT",
"groupName": "Posts",
"responseType": "Volo.Blogging.Posts.PostWithDetailsDto",
"responseTypeAsJson": "{\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n}",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
},
{
"name": "input",
"type": "UpdatePostDto"
}
]
},
{
"path": "api/blogging/posts/user/{userId}",
"method": "GET",
"groupName": "Posts",
"responseType": "System.Collections.Generic.List`1[Volo.Blogging.Posts.PostWithDetailsDto]",
"responseTypeAsJson": "[\r\n {\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n]",
"parameterDescriptions": [
{
"name": "userId",
"type": "Guid"
}
]
},
{
"path": "api/blogging/posts/{blogId}/latest/{count}",
"method": "GET",
"groupName": "Posts",
"responseType": "System.Collections.Generic.List`1[Volo.Blogging.Posts.PostWithDetailsDto]",
"responseTypeAsJson": "[\r\n {\r\n \"blogId\": \"00000000-0000-0000-0000-000000000000\",\r\n \"title\": \"string\",\r\n \"coverImage\": \"string\",\r\n \"url\": \"string\",\r\n \"content\": \"string\",\r\n \"description\": \"string\",\r\n \"readCount\": 0,\r\n \"commentCount\": 0,\r\n \"writer\": {\r\n \"tenantId\": null,\r\n \"name\": \"string\",\r\n \"surname\": \"string\",\r\n \"userName\": \"string\",\r\n \"email\": \"string\",\r\n \"emailConfirmed\": false,\r\n \"phoneNumber\": \"string\",\r\n \"phoneNumberConfirmed\": false,\r\n \"webSite\": \"string\",\r\n \"twitter\": \"string\",\r\n \"github\": \"string\",\r\n \"linkedin\": \"string\",\r\n \"company\": \"string\",\r\n \"jobTitle\": \"string\",\r\n \"biography\": \"string\",\r\n \"extraProperties\": {\r\n \"string\": \"object\"\r\n },\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n },\r\n \"tags\": [\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n ],\r\n \"concurrencyStamp\": \"string\",\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n]",
"parameterDescriptions": [
{
"name": "blogId",
"type": "Guid"
},
{
"name": "count",
"type": "Int32"
}
]
},
{
"path": "api/blogging/posts/{id}",
"method": "DELETE",
"groupName": "Posts",
"responseType": "System.Void",
"responseTypeAsJson": "",
"parameterDescriptions": [
{
"name": "id",
"type": "Guid"
}
]
},
{
"path": "api/blogging/tags/popular/{blogId}",
"method": "GET",
"groupName": "Tags",
"responseType": "System.Collections.Generic.List`1[Volo.Blogging.Tagging.Dtos.TagDto]",
"responseTypeAsJson": "[\r\n {\r\n \"name\": \"string\",\r\n \"description\": \"string\",\r\n \"usageCount\": 0,\r\n \"isDeleted\": false,\r\n \"deleterId\": null,\r\n \"deletionTime\": null,\r\n \"lastModificationTime\": null,\r\n \"lastModifierId\": null,\r\n \"creationTime\": \"0001-01-01T00:00:00\",\r\n \"creatorId\": null,\r\n \"id\": \"00000000-0000-0000-0000-000000000000\"\r\n }\r\n]",
"parameterDescriptions": [
{
"name": "blogId",
"type": "Guid"
},
{
"name": "ResultCount",
"type": "Int32"
},
{
"name": "MinimumPostCount",
"type": "Nullable<Int32>"
}
]
}
],
"contentType": "httpApi",
"name": "Defined Http Apis",
"summary": null
} }
] ]
} }

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

@ -16,7 +16,7 @@ namespace Volo.Blogging.Blogs
public virtual async Task<Blog> FindByShortNameAsync(string shortName, CancellationToken cancellationToken = default) public virtual async Task<Blog> FindByShortNameAsync(string shortName, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.ShortName == shortName, GetCancellationToken(cancellationToken)); return await (await GetQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.ShortName == shortName, GetCancellationToken(cancellationToken));
} }
} }
} }

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

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.Domain.Repositories.MongoDB;
@ -18,7 +19,7 @@ namespace Volo.Blogging.Comments
public virtual async Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default) public virtual async Task<List<Comment>> GetListOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(a => a.PostId == postId) .Where(a => a.PostId == postId)
.OrderBy(a => a.CreationTime) .OrderBy(a => a.CreationTime)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
@ -26,19 +27,19 @@ namespace Volo.Blogging.Comments
public virtual async Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default) public virtual async Task<int> GetCommentCountOfPostAsync(Guid postId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.CountAsync(a => a.PostId == postId, GetCancellationToken(cancellationToken)); .CountAsync(a => a.PostId == postId, GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default) public virtual async Task<List<Comment>> GetRepliesOfComment(Guid id, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(a => a.RepliedCommentId == id).ToListAsync(GetCancellationToken(cancellationToken)); .Where(a => a.RepliedCommentId == id).ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default) public virtual async Task DeleteOfPost(Guid id, CancellationToken cancellationToken = default)
{ {
var recordsToDelete = (await GetMongoQueryableAsync(cancellationToken)).Where(pt => pt.PostId == id); var recordsToDelete = (await GetQueryableAsync(cancellationToken)).Where(pt => pt.PostId == id);
foreach (var record in recordsToDelete) foreach (var record in recordsToDelete)
{ {

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

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using MongoDB.Driver; using MongoDB.Driver;
using MongoDB.Driver.Linq; using MongoDB.Driver.Linq;
using Nito.AsyncEx; using Nito.AsyncEx;
@ -20,13 +21,13 @@ namespace Volo.Blogging.Posts
public virtual async Task<List<Post>> GetPostsByBlogId(Guid id, CancellationToken cancellationToken = default) public virtual async Task<List<Post>> GetPostsByBlogId(Guid id, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)).Where(p => p.BlogId == id).OrderByDescending(p => p.CreationTime).ToListAsync(GetCancellationToken(cancellationToken)); return await (await GetQueryableAsync(cancellationToken)).Where(p => p.BlogId == id).OrderByDescending(p => p.CreationTime).ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null, CancellationToken cancellationToken = default) public virtual async Task<bool> IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null, CancellationToken cancellationToken = default)
{ {
var query = (await GetMongoQueryableAsync(cancellationToken)).Where(p => blogId == p.BlogId && p.Url == url); var query = (await GetQueryableAsync(cancellationToken)).Where(p => blogId == p.BlogId && p.Url == url);
if (excludingPostId != null) if (excludingPostId != null)
{ {
@ -38,7 +39,7 @@ namespace Volo.Blogging.Posts
public virtual async Task<Post> GetPostByUrl(Guid blogId, string url, CancellationToken cancellationToken = default) public virtual async Task<Post> GetPostByUrl(Guid blogId, string url, CancellationToken cancellationToken = default)
{ {
var post = await (await GetMongoQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url, GetCancellationToken(cancellationToken)); var post = await (await GetQueryableAsync(cancellationToken)).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url, GetCancellationToken(cancellationToken));
if (post == null) if (post == null)
{ {
@ -50,7 +51,7 @@ namespace Volo.Blogging.Posts
public virtual async Task<List<Post>> GetOrderedList(Guid blogId, bool @descending = false, CancellationToken cancellationToken = default) public virtual async Task<List<Post>> GetOrderedList(Guid blogId, bool @descending = false, CancellationToken cancellationToken = default)
{ {
var query = (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.BlogId == blogId); var query = (await GetQueryableAsync(cancellationToken)).Where(x => x.BlogId == blogId);
if (!descending) if (!descending)
{ {
@ -62,7 +63,7 @@ namespace Volo.Blogging.Posts
public virtual async Task<List<Post>> GetListByUserIdAsync(Guid userId, CancellationToken cancellationToken = default) public virtual async Task<List<Post>> GetListByUserIdAsync(Guid userId, CancellationToken cancellationToken = default)
{ {
var query = (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.CreatorId == userId) var query = (await GetQueryableAsync(cancellationToken)).Where(x => x.CreatorId == userId)
.OrderByDescending(x => x.CreationTime); .OrderByDescending(x => x.CreationTime);
return await query.ToListAsync(GetCancellationToken(cancellationToken)); return await query.ToListAsync(GetCancellationToken(cancellationToken));
@ -70,7 +71,7 @@ namespace Volo.Blogging.Posts
public virtual async Task<List<Post>> GetLatestBlogPostsAsync(Guid blogId, int count, CancellationToken cancellationToken = default) public virtual async Task<List<Post>> GetLatestBlogPostsAsync(Guid blogId, int count, CancellationToken cancellationToken = default)
{ {
var query = (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.BlogId == blogId) var query = (await GetQueryableAsync(cancellationToken)).Where(x => x.BlogId == blogId)
.OrderByDescending(x => x.CreationTime) .OrderByDescending(x => x.CreationTime)
.Take(count); .Take(count);

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

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

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

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using Volo.Abp.MongoDB; using Volo.Abp.MongoDB;
using Volo.Abp.Users.MongoDB; using Volo.Abp.Users.MongoDB;
using Volo.Blogging.MongoDB; using Volo.Blogging.MongoDB;
@ -17,7 +18,7 @@ namespace Volo.Blogging.Users
public virtual async Task<List<BlogUser>> GetUsersAsync(int maxCount, string filter, CancellationToken cancellationToken = default) public virtual async Task<List<BlogUser>> GetUsersAsync(int maxCount, string filter, CancellationToken cancellationToken = default)
{ {
var query = await GetMongoQueryableAsync(cancellationToken); var query = await GetQueryableAsync(cancellationToken);
if (!string.IsNullOrWhiteSpace(filter)) if (!string.IsNullOrWhiteSpace(filter))
{ {

8
modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.csproj

@ -7,10 +7,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="EphemeralMongo.Core" /> <PackageReference Include="MongoSandbox.Core" />
<PackageReference Include="EphemeralMongo6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" /> <PackageReference Include="MongoSandbox6.runtime.linux-x64" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="EphemeralMongo6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> <PackageReference Include="MongoSandbox6.runtime.osx-x64" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
<PackageReference Include="EphemeralMongo6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" /> <PackageReference Include="MongoSandbox6.runtime.win-x64" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
<ProjectReference Include="..\..\src\Volo.Blogging.MongoDB\Volo.Blogging.MongoDB.csproj" /> <ProjectReference Include="..\..\src\Volo.Blogging.MongoDB\Volo.Blogging.MongoDB.csproj" />
<ProjectReference Include="..\Volo.Blogging.TestBase\Volo.Blogging.TestBase.csproj" /> <ProjectReference Include="..\Volo.Blogging.TestBase\Volo.Blogging.TestBase.csproj" />
</ItemGroup> </ItemGroup>

2
modules/blogging/test/Volo.Blogging.MongoDB.Tests/Volo/Blogging/MongoDB/MongoDbFixture.cs

@ -1,5 +1,5 @@
using System; using System;
using EphemeralMongo; using MongoSandbox;
public class MongoDbFixture : IDisposable public class MongoDbFixture : IDisposable
{ {

2
modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/Volo.CmsKit.HttpApi.Host.abppkg.analyze.json

@ -1,6 +1,6 @@
{ {
"name": "Volo.CmsKit.HttpApi.Host", "name": "Volo.CmsKit.HttpApi.Host",
"hash": "1b93c2e5623eede67e84115d4c3c3265", "hash": "",
"contents": [ "contents": [
{ {
"namespace": "Volo.CmsKit", "namespace": "Volo.CmsKit",

2
modules/cms-kit/host/Volo.CmsKit.Web.Host/Volo.CmsKit.Web.Host.abppkg.analyze.json

@ -1,6 +1,6 @@
{ {
"name": "Volo.CmsKit.Web.Host", "name": "Volo.CmsKit.Web.Host",
"hash": "4e765df6a6f987aba4c051f2106178ac", "hash": "",
"contents": [ "contents": [
{ {
"namespace": "Volo.CmsKit", "namespace": "Volo.CmsKit",

196
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo.CmsKit.Admin.Application.Contracts.abppkg.analyze.json

@ -58,202 +58,6 @@
"contentType": "abpModule", "contentType": "abpModule",
"name": "CmsKitAdminApplicationContractsModule", "name": "CmsKitAdminApplicationContractsModule",
"summary": null "summary": null
},
{
"displayName": "Comment management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Comments",
"summary": null
},
{
"displayName": "Delete",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Comments.Delete",
"summary": null
},
{
"displayName": "Permission:Comments.Update",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Comments.Update",
"summary": null
},
{
"displayName": "Permission:Comments.SettingManagement",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Comments.SettingManagement",
"summary": null
},
{
"displayName": "Tag management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Tags",
"summary": null
},
{
"displayName": "Create",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Tags.Create",
"summary": null
},
{
"displayName": "Update",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Tags.Update",
"summary": null
},
{
"displayName": "Delete",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Tags.Delete",
"summary": null
},
{
"displayName": "Page management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Pages",
"summary": null
},
{
"displayName": "Create",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Pages.Create",
"summary": null
},
{
"displayName": "Update",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Pages.Update",
"summary": null
},
{
"displayName": "Delete",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Pages.Delete",
"summary": null
},
{
"displayName": "Set as home page",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Pages.SetAsHomePage",
"summary": null
},
{
"displayName": "Blog management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Blogs",
"summary": null
},
{
"displayName": "Create",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Blogs.Create",
"summary": null
},
{
"displayName": "Update",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Blogs.Update",
"summary": null
},
{
"displayName": "Delete",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Blogs.Delete",
"summary": null
},
{
"displayName": "Features",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Blogs.Features",
"summary": null
},
{
"displayName": "Blog post management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.BlogPosts",
"summary": null
},
{
"displayName": "Create",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.BlogPosts.Create",
"summary": null
},
{
"displayName": "Update",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.BlogPosts.Update",
"summary": null
},
{
"displayName": "Delete",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.BlogPosts.Delete",
"summary": null
},
{
"displayName": "Publish",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.BlogPosts.Publish",
"summary": null
},
{
"displayName": "Menu management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Menus",
"summary": null
},
{
"displayName": "Create",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Menus.Create",
"summary": null
},
{
"displayName": "Update",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Menus.Update",
"summary": null
},
{
"displayName": "Delete",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.Menus.Delete",
"summary": null
},
{
"displayName": "Global resources",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKit.GlobalResources",
"summary": null
} }
] ]
} }

136
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo.CmsKit.Common.Application.abppkg.analyze.json

@ -74,6 +74,142 @@
"name": "CmsKitCommonApplicationModule", "name": "CmsKitCommonApplicationModule",
"summary": null "summary": null
}, },
{
"eventHandlerType": "Local",
"namespace": "Volo.CmsKit.Menus",
"subscribedEvents": [
{
"underlyingType": {
"name": "MenuItem",
"namespace": "Volo.CmsKit.Menus",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.Menus.MenuItem"
},
"name": "EntityUpdatedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityUpdatedEventData`1"
},
{
"underlyingType": {
"name": "MenuItem",
"namespace": "Volo.CmsKit.Menus",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.Menus.MenuItem"
},
"name": "EntityDeletedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityDeletedEventData`1"
},
{
"underlyingType": {
"name": "MenuItem",
"namespace": "Volo.CmsKit.Menus",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.Menus.MenuItem"
},
"name": "EntityCreatedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityCreatedEventData`1"
}
],
"implementingInterfaces": [
{
"name": "ILocalEventHandler<EntityUpdatedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityUpdatedEventData`1>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ILocalEventHandler<EntityDeletedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityDeletedEventData`1>"
},
{
"name": "ILocalEventHandler<EntityCreatedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityCreatedEventData`1>"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "MenuChangedHandler",
"summary": null
},
{
"eventHandlerType": "Local",
"namespace": "Volo.CmsKit.Blogs",
"subscribedEvents": [
{
"underlyingType": {
"name": "BlogFeature",
"namespace": "Volo.CmsKit.Blogs",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.Blogs.BlogFeature"
},
"name": "EntityCreatedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityCreatedEventData`1"
},
{
"underlyingType": {
"name": "BlogFeature",
"namespace": "Volo.CmsKit.Blogs",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.Blogs.BlogFeature"
},
"name": "EntityUpdatedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityUpdatedEventData`1"
}
],
"implementingInterfaces": [
{
"name": "ILocalEventHandler<EntityCreatedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityCreatedEventData`1>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ILocalEventHandler<EntityUpdatedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityUpdatedEventData`1>"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "BlogFeatureChangedHandler",
"summary": null
},
{ {
"namespace": "Volo.CmsKit.Tags", "namespace": "Volo.CmsKit.Tags",
"baseClass": { "baseClass": {

11
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.abppkg.analyze.json

@ -68,17 +68,6 @@
"contentType": "abpModule", "contentType": "abpModule",
"name": "CmsKitDomainSharedModule", "name": "CmsKitDomainSharedModule",
"summary": null "summary": null
},
{
"defaultValue": "false",
"displayName": "CmsKit.Comments.RequireApprovement",
"description": "",
"isVisibleToClient": true,
"isInherited": true,
"isEncrypted": false,
"contentType": "setting",
"name": "CmsKit.Comments.RequireApprovement",
"summary": null
} }
] ]
} }

13
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json

@ -241,6 +241,19 @@
"CssClass": "فئة CSS", "CssClass": "فئة CSS",
"TagsHelpText": "يجب أن تكون العلامات مفصولة بفواصل (على سبيل المثال: tag1، tag2، tag3)", "TagsHelpText": "يجب أن تكون العلامات مفصولة بفواصل (على سبيل المثال: tag1، tag2، tag3)",
"ThisPartOfContentCouldntBeLoaded": "لا يمكن تحميل هذا الجزء من المحتوى.", "ThisPartOfContentCouldntBeLoaded": "لا يمكن تحميل هذا الجزء من المحتوى.",
"JustNow": "الآن",
"MinuteAgo": "دقيقة واحدة مضت",
"MinutesAgo": "{0} دقائق مضت",
"HourAgo": "ساعة واحدة مضت",
"HoursAgo": "{0} ساعات مضت",
"YesterdayAt": "أمس في {0}",
"DayAt": "{0} في {1}",
"MonthDayAt": "{0} {1} في {2}",
"FullDate": "{0} {1} {2}",
"Minute": "د",
"Hour": "س",
"Day": "ي",
"Week": "أ",
"DuplicateCommentAttemptMessage": "تم اكتشاف محاولة نشر تعليق مكررة. لقد تم بالفعل تقديم تعليقك.", "DuplicateCommentAttemptMessage": "تم اكتشاف محاولة نشر تعليق مكررة. لقد تم بالفعل تقديم تعليقك.",
"ChooseAnActionForBlog": "اختر إجراءً للمدونة", "ChooseAnActionForBlog": "اختر إجراءً للمدونة",
"AssignBlogPostsToOtherBlog": "تعيين مشاركات المدونة إلى مدونة أخرى", "AssignBlogPostsToOtherBlog": "تعيين مشاركات المدونة إلى مدونة أخرى",

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

@ -259,6 +259,19 @@
"CommentAlertMessage": "There are {0} comments waiting for approval", "CommentAlertMessage": "There are {0} comments waiting for approval",
"Settings:Menu:CmsKit": "CMS", "Settings:Menu:CmsKit": "CMS",
"CommentsAwaitingApproval": "Comments Awaiting Approval", "CommentsAwaitingApproval": "Comments Awaiting Approval",
"JustNow": "Just now",
"MinuteAgo": "1 minute ago",
"MinutesAgo": "{0} minutes ago",
"HourAgo": "1 hour ago",
"HoursAgo": "{0} hours ago",
"YesterdayAt": "Yesterday at {0}",
"DayAt": "{0} at {1}",
"MonthDayAt": "{0} {1} at {2}",
"FullDate": "{0} {1} {2}",
"Minute": "m",
"Hour": "h",
"Day": "d",
"Week": "w",
"CommentSubmittedForApproval": "Your comment has been submitted for approval.", "CommentSubmittedForApproval": "Your comment has been submitted for approval.",
"ChooseAnActionForBlog": "Choose an action for the blog", "ChooseAnActionForBlog": "Choose an action for the blog",
"AssignBlogPostsToOtherBlog": "Assign blog posts to another blog", "AssignBlogPostsToOtherBlog": "Assign blog posts to another blog",

82
modules/cms-kit/src/Volo.CmsKit.Domain/Volo.CmsKit.Domain.abppkg.analyze.json

@ -5627,6 +5627,88 @@
"contentType": "repositoryInterface", "contentType": "repositoryInterface",
"name": "IBlogRepository", "name": "IBlogRepository",
"summary": null "summary": null
},
{
"eventHandlerType": "Distributed",
"namespace": "Volo.CmsKit.Users",
"subscribedEvents": [
{
"underlyingType": {
"name": "UserEto",
"namespace": "Volo.Abp.Users",
"declaringAssemblyName": "Volo.Abp.Users.Abstractions",
"fullName": "Volo.Abp.Users.UserEto"
},
"name": "EntityUpdatedEto`1",
"namespace": "Volo.Abp.Domain.Entities.Events.Distributed",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain.Shared",
"fullName": "Volo.Abp.Domain.Entities.Events.Distributed.EntityUpdatedEto`1"
}
],
"implementingInterfaces": [
{
"name": "IDistributedEventHandler<EntityUpdatedEto`1>",
"namespace": "Volo.Abp.EventBus.Distributed",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.Distributed.IDistributedEventHandler<EntityUpdatedEto`1>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "CmsUserSynchronizer",
"summary": null
},
{
"eventHandlerType": "Local",
"namespace": "Volo.CmsKit.Menus",
"subscribedEvents": [
{
"underlyingType": {
"name": "Page",
"namespace": "Volo.CmsKit.Pages",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.Pages.Page"
},
"name": "EntityUpdatedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityUpdatedEventData`1"
}
],
"implementingInterfaces": [
{
"name": "ILocalEventHandler<EntityUpdatedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityUpdatedEventData`1>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "PageChangedHandler",
"summary": null
} }
] ]
} }

87
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo.CmsKit.EntityFrameworkCore.abppkg.analyze.json

@ -72,7 +72,92 @@
{ {
"namespace": "Volo.CmsKit.EntityFrameworkCore", "namespace": "Volo.CmsKit.EntityFrameworkCore",
"connectionStringName": "CmsKit", "connectionStringName": "CmsKit",
"databaseTables": [], "databaseTables": [
{
"entityFullName": "Volo.CmsKit.Comments.Comment",
"contentType": "databaseTable",
"name": "Comments",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Users.CmsUser",
"contentType": "databaseTable",
"name": "User",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Reactions.UserReaction",
"contentType": "databaseTable",
"name": "Reactions",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Ratings.Rating",
"contentType": "databaseTable",
"name": "Ratings",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Tags.Tag",
"contentType": "databaseTable",
"name": "Tags",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Tags.EntityTag",
"contentType": "databaseTable",
"name": "EntityTags",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Pages.Page",
"contentType": "databaseTable",
"name": "Pages",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Blogs.Blog",
"contentType": "databaseTable",
"name": "Blogs",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Blogs.BlogPost",
"contentType": "databaseTable",
"name": "BlogPosts",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Blogs.BlogFeature",
"contentType": "databaseTable",
"name": "BlogFeatures",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.MediaDescriptors.MediaDescriptor",
"contentType": "databaseTable",
"name": "MediaDescriptors",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.Menus.MenuItem",
"contentType": "databaseTable",
"name": "MenuItems",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.GlobalResources.GlobalResource",
"contentType": "databaseTable",
"name": "GlobalResources",
"summary": null
},
{
"entityFullName": "Volo.CmsKit.MarkedItems.UserMarkedItem",
"contentType": "databaseTable",
"name": "UserMarkedItems",
"summary": null
}
],
"replacedDbContexts": [], "replacedDbContexts": [],
"modelBuilderExtensionMethods": [ "modelBuilderExtensionMethods": [
{ {

4
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogFeatureRepository.cs

@ -25,14 +25,14 @@ public class MongoBlogFeatureRepository : MongoDbRepository<ICmsKitMongoDbContex
public virtual async Task<List<BlogFeature>> GetListAsync(Guid blogId, CancellationToken cancellationToken = default) public virtual async Task<List<BlogFeature>> GetListAsync(Guid blogId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(x => x.BlogId == blogId) .Where(x => x.BlogId == blogId)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<BlogFeature>> GetListAsync(Guid blogId, List<string> featureNames, CancellationToken cancellationToken = default) public virtual async Task<List<BlogFeature>> GetListAsync(Guid blogId, List<string> featureNames, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(x => x.BlogId == blogId && featureNames.Contains(x.FeatureName)) .Where(x => x.BlogId == blogId && featureNames.Contains(x.FeatureName))
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }

22
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogPostRepository.cs

@ -44,7 +44,7 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
x.Slug.ToLower() == slug, x.Slug.ToLower() == slug,
cancellationToken: token); cancellationToken: token);
blogPost.Author = await (await GetMongoQueryableAsync<CmsUser>(token)).FirstOrDefaultAsync(x => x.Id == blogPost.AuthorId, token); blogPost.Author = await (await GetQueryableAsync<CmsUser>(token)).FirstOrDefaultAsync(x => x.Id == blogPost.AuthorId, token);
return blogPost; return blogPost;
} }
@ -64,13 +64,13 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
var favoriteUserFilteredEntityIds = await GetFavoriteEntityIdsByUserId(favoriteUserId, cancellationToken); var favoriteUserFilteredEntityIds = await GetFavoriteEntityIdsByUserId(favoriteUserId, cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(tagFilteredEntityIds.Any(), x => tagFilteredEntityIds.Contains(x.Id)) .WhereIf(tagFilteredEntityIds.Any(), x => tagFilteredEntityIds.Contains(x.Id))
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(favoriteUserFilteredEntityIds.Any(), x => favoriteUserFilteredEntityIds.Contains(x.Id)) .WhereIf(favoriteUserFilteredEntityIds.Any(), x => favoriteUserFilteredEntityIds.Contains(x.Id))
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter)) .WhereIf(!string.IsNullOrWhiteSpace(filter), x => x.Title.Contains(filter) || x.Slug.Contains(filter))
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(blogId.HasValue, x => x.BlogId == blogId) .WhereIf(blogId.HasValue, x => x.BlogId == blogId)
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(authorId.HasValue, x => x.AuthorId == authorId) .WhereIf(authorId.HasValue, x => x.AuthorId == authorId)
.WhereIf<BlogPost, IMongoQueryable<BlogPost>>(statusFilter.HasValue, x => x.Status == statusFilter) .WhereIf(statusFilter.HasValue, x => x.Status == statusFilter)
.CountAsync(cancellationToken); .CountAsync(cancellationToken);
} }
@ -174,7 +174,7 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
Check.NotNullOrEmpty(slug, nameof(slug)); Check.NotNullOrEmpty(slug, nameof(slug));
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
var queryable = await GetMongoQueryableAsync(cancellationToken); var queryable = await GetQueryableAsync(cancellationToken);
return await queryable.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken); return await queryable.AnyAsync(x => x.BlogId == blogId && x.Slug.ToLower() == slug, cancellationToken);
} }
@ -225,14 +225,14 @@ public class MongoBlogPostRepository : MongoDbRepository<CmsKitMongoDbContext, B
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.AnyAsync(x => x.Status == BlogPostStatus.WaitingForReview, cancellationToken); .AnyAsync(x => x.Status == BlogPostStatus.WaitingForReview, cancellationToken);
} }
public async Task UpdateBlogAsync(Guid sourceBlogId, Guid? targetBlogId, CancellationToken cancellationToken = default) public async Task UpdateBlogAsync(Guid sourceBlogId, Guid? targetBlogId, CancellationToken cancellationToken = default)
{ {
cancellationToken = GetCancellationToken(cancellationToken); cancellationToken = GetCancellationToken(cancellationToken);
var blogPosts = await (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.BlogId == sourceBlogId).ToListAsync(cancellationToken); var blogPosts = await (await GetQueryableAsync(cancellationToken)).Where(x => x.BlogId == sourceBlogId).ToListAsync(cancellationToken);
if (targetBlogId.HasValue) if (targetBlogId.HasValue)
{ {
foreach (var blogPost in blogPosts) foreach (var blogPost in blogPosts)

13
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Blogs/MongoBlogRepository.cs

@ -23,13 +23,13 @@ public class MongoBlogRepository : MongoDbRepository<ICmsKitMongoDbContext, Blog
public virtual async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default) public virtual async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
{ {
var token = GetCancellationToken(cancellationToken); var token = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(token)).AnyAsync(x => x.Id == id, token); return await (await GetQueryableAsync(token)).AnyAsync(x => x.Id == id, token);
} }
public virtual async Task<bool> SlugExistsAsync(string slug, CancellationToken cancellationToken = default) public virtual async Task<bool> SlugExistsAsync(string slug, CancellationToken cancellationToken = default)
{ {
var token = GetCancellationToken(cancellationToken); var token = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(token)).AnyAsync(x => x.Slug == slug, token); return await (await GetQueryableAsync(token)).AnyAsync(x => x.Slug == slug, token);
} }
public virtual async Task<List<Blog>> GetListAsync( public virtual async Task<List<Blog>> GetListAsync(
@ -44,8 +44,7 @@ public class MongoBlogRepository : MongoDbRepository<ICmsKitMongoDbContext, Blog
var query = await GetListQueryAsync(filter, token); var query = await GetListQueryAsync(filter, token);
return await query.OrderBy(sorting.IsNullOrEmpty() ? "creationTime desc" : sorting) return await query.OrderBy(sorting.IsNullOrEmpty() ? "creationTime desc" : sorting)
.As<IMongoQueryable<Blog>>() .PageBy(skipCount, maxResultCount)
.PageBy<Blog, IMongoQueryable<Blog>>(skipCount, maxResultCount)
.ToListAsync(token); .ToListAsync(token);
} }
@ -63,7 +62,7 @@ public class MongoBlogRepository : MongoDbRepository<ICmsKitMongoDbContext, Blog
var blogIds = blogs.OrderBy(sorting.IsNullOrEmpty() ? "creationTime desc" : sorting) var blogIds = blogs.OrderBy(sorting.IsNullOrEmpty() ? "creationTime desc" : sorting)
.PageBy(skipCount, maxResultCount).Select(x => x.Id).ToList(); .PageBy(skipCount, maxResultCount).Select(x => x.Id).ToList();
var blogPostCount = await (await GetMongoQueryableAsync<BlogPost>(token)) var blogPostCount = await (await GetQueryableAsync<BlogPost>(token))
.Where(blogPost => blogIds.Contains(blogPost.Id)) .Where(blogPost => blogIds.Contains(blogPost.Id))
.GroupBy(blogPost => blogPost.BlogId) .GroupBy(blogPost => blogPost.BlogId)
.Select(x => new .Select(x => new
@ -82,7 +81,7 @@ public class MongoBlogRepository : MongoDbRepository<ICmsKitMongoDbContext, Blog
var query = await GetListQueryAsync(filter, token); var query = await GetListQueryAsync(filter, token);
return await query.As<IMongoQueryable<Blog>>().LongCountAsync(token); return await query.LongCountAsync(token);
} }
public virtual Task<Blog> GetBySlugAsync([NotNull] string slug, CancellationToken cancellationToken = default) public virtual Task<Blog> GetBySlugAsync([NotNull] string slug, CancellationToken cancellationToken = default)
@ -93,7 +92,7 @@ public class MongoBlogRepository : MongoDbRepository<ICmsKitMongoDbContext, Blog
protected virtual async Task<IQueryable<Blog>> GetListQueryAsync(string filter = null, CancellationToken cancellationToken = default) protected virtual async Task<IQueryable<Blog>> GetListQueryAsync(string filter = null, CancellationToken cancellationToken = default)
{ {
return (await GetMongoQueryableAsync(cancellationToken)) return (await GetQueryableAsync(cancellationToken))
.WhereIf(!filter.IsNullOrWhiteSpace(), b => b.Name.Contains(filter)); .WhereIf(!filter.IsNullOrWhiteSpace(), b => b.Name.Contains(filter));
} }
} }

24
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Comments/MongoCommentRepository.cs

@ -61,19 +61,18 @@ public class MongoCommentRepository : MongoDbRepository<ICmsKitMongoDbContext, C
token); token);
var comments = await query.OrderBy(sorting.IsNullOrEmpty() ? "creationTime desc" : sorting) var comments = await query.OrderBy(sorting.IsNullOrEmpty() ? "creationTime desc" : sorting)
.As<IMongoQueryable<Comment>>() .PageBy(skipCount, maxResultCount)
.PageBy<Comment, IMongoQueryable<Comment>>(skipCount, maxResultCount)
.ToListAsync(token); .ToListAsync(token);
var commentIds = comments.Select(x => x.Id).ToList(); var commentIds = comments.Select(x => x.Id).ToList();
var authorsQuery = from comment in (await GetMongoQueryableAsync(token)) var authorsQuery = from comment in (await GetQueryableAsync(token))
join user in (await GetDbContextAsync(token)).CmsUsers on comment.CreatorId equals user.Id join user in (await GetDbContextAsync(token)).CmsUsers on comment.CreatorId equals user.Id
where commentIds.Contains(comment.Id) where commentIds.Contains(comment.Id)
orderby comment.CreationTime orderby comment.CreationTime
select user; select user;
var authors = await ApplyDataFilters<IMongoQueryable<CmsUser>, CmsUser>(authorsQuery).ToListAsync(token); var authors = await ApplyDataFilters<IQueryable<CmsUser>, CmsUser>(authorsQuery).ToListAsync(token);
return comments return comments
.Select( .Select(
@ -104,8 +103,7 @@ public class MongoCommentRepository : MongoDbRepository<ICmsKitMongoDbContext, C
commentApproveState, commentApproveState,
cancellationToken); cancellationToken);
return await query.As<IMongoQueryable<Comment>>() return await query.LongCountAsync(GetCancellationToken(cancellationToken));
.LongCountAsync(GetCancellationToken(cancellationToken));
} }
public virtual async Task<List<CommentWithAuthorQueryResultItem>> GetListWithAuthorsAsync( public virtual async Task<List<CommentWithAuthorQueryResultItem>> GetListWithAuthorsAsync(
@ -117,15 +115,15 @@ public class MongoCommentRepository : MongoDbRepository<ICmsKitMongoDbContext, C
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
var authorsQuery = from comment in (await GetMongoQueryableAsync(cancellationToken)) var authorsQuery = from comment in (await GetQueryableAsync(cancellationToken))
join user in (await GetDbContextAsync(cancellationToken)).CmsUsers on comment.CreatorId equals user.Id join user in (await GetDbContextAsync(cancellationToken)).CmsUsers on comment.CreatorId equals user.Id
where entityType == comment.EntityType && entityId == comment.EntityId where entityType == comment.EntityType && entityId == comment.EntityId
orderby comment.CreationTime orderby comment.CreationTime
select user; select user;
var authors = await ApplyDataFilters<IMongoQueryable<CmsUser>, CmsUser>(authorsQuery).ToListAsync(GetCancellationToken(cancellationToken)); var authors = await ApplyDataFilters<IQueryable<CmsUser>, CmsUser>(authorsQuery).ToListAsync(GetCancellationToken(cancellationToken));
var commentsQuery = (await GetMongoQueryableAsync(cancellationToken)) var commentsQuery = (await GetQueryableAsync(cancellationToken))
.Where(c => c.EntityId == entityId && c.EntityType == entityType); .Where(c => c.EntityId == entityId && c.EntityType == entityType);
commentsQuery = commentApproveState switch { commentsQuery = commentApproveState switch {
@ -152,7 +150,7 @@ public class MongoCommentRepository : MongoDbRepository<ICmsKitMongoDbContext, C
Comment comment, Comment comment,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var replies = await (await GetMongoQueryableAsync(cancellationToken)) var replies = await (await GetQueryableAsync(cancellationToken))
.Where(x => x.RepliedCommentId == comment.Id) .Where(x => x.RepliedCommentId == comment.Id)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
@ -172,7 +170,7 @@ public class MongoCommentRepository : MongoDbRepository<ICmsKitMongoDbContext, C
public virtual async Task<bool> ExistsAsync(string idempotencyToken, CancellationToken cancellationToken = default) public virtual async Task<bool> ExistsAsync(string idempotencyToken, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.AnyAsync(x => x.IdempotencyToken == idempotencyToken, GetCancellationToken(cancellationToken)); .AnyAsync(x => x.IdempotencyToken == idempotencyToken, GetCancellationToken(cancellationToken));
} }
@ -187,11 +185,11 @@ public class MongoCommentRepository : MongoDbRepository<ICmsKitMongoDbContext, C
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
{ {
var queryable = await GetMongoQueryableAsync(cancellationToken); var queryable = await GetQueryableAsync(cancellationToken);
if (!string.IsNullOrEmpty(authorUsername)) if (!string.IsNullOrEmpty(authorUsername))
{ {
var author = await (await GetMongoQueryableAsync<CmsUser>(cancellationToken)).FirstOrDefaultAsync(x => x.UserName == authorUsername, cancellationToken: cancellationToken); var author = await (await GetQueryableAsync<CmsUser>(cancellationToken)).FirstOrDefaultAsync(x => x.UserName == authorUsername, cancellationToken: cancellationToken);
var authorId = author?.Id ?? Guid.Empty; var authorId = author?.Id ?? Guid.Empty;

6
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/MarkedItems/MongoUserMarkedItemRepository.cs

@ -24,7 +24,7 @@ public class MongoUserMarkedItemRepository : MongoDbRepository<ICmsKitMongoDbCon
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNull(entityId, nameof(entityId)); Check.NotNull(entityId, nameof(entityId));
var entity = await (await GetMongoQueryableAsync(cancellationToken)) var entity = await (await GetQueryableAsync(cancellationToken))
.Where(x => .Where(x =>
x.CreatorId == userId && x.CreatorId == userId &&
x.EntityType == entityType && x.EntityType == entityType &&
@ -39,7 +39,7 @@ public class MongoUserMarkedItemRepository : MongoDbRepository<ICmsKitMongoDbCon
Check.NotNull(userId, nameof(userId)); Check.NotNull(userId, nameof(userId));
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
return await(await GetMongoQueryableAsync(cancellationToken)) return await(await GetQueryableAsync(cancellationToken))
.Where(x => .Where(x =>
x.CreatorId == userId && x.CreatorId == userId &&
x.EntityType == entityType) x.EntityType == entityType)
@ -49,7 +49,7 @@ public class MongoUserMarkedItemRepository : MongoDbRepository<ICmsKitMongoDbCon
public virtual async Task<List<string>> GetEntityIdsFilteredByUserAsync([NotNull] Guid userId, [NotNull] string entityType, [CanBeNull] Guid? tenantId = null, CancellationToken cancellationToken = default) public virtual async Task<List<string>> GetEntityIdsFilteredByUserAsync([NotNull] Guid userId, [NotNull] string entityType, [CanBeNull] Guid? tenantId = null, CancellationToken cancellationToken = default)
{ {
var dbContext = await GetDbContextAsync(); var dbContext = await GetDbContextAsync();
var userMarkedItemQueryable = await GetMongoQueryableAsync(GetCancellationToken(cancellationToken)); var userMarkedItemQueryable = await GetQueryableAsync(GetCancellationToken(cancellationToken));
var resultQueryable = userMarkedItemQueryable var resultQueryable = userMarkedItemQueryable
.Where(x => x.CreatorId == userId .Where(x => x.CreatorId == userId

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

@ -26,8 +26,8 @@ public class MongoPageRepository : MongoDbRepository<ICmsKitMongoDbContext, Page
{ {
var cancellation = GetCancellationToken(cancellationToken); var cancellation = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellation)) return await (await GetQueryableAsync(cancellation))
.WhereIf<Page, IMongoQueryable<Page>>( .WhereIf(
!filter.IsNullOrWhiteSpace(), !filter.IsNullOrWhiteSpace(),
u => u =>
u.Title.ToLower().Contains(filter.ToLower()) || u.Slug.Contains(filter) u.Title.ToLower().Contains(filter.ToLower()) || u.Slug.Contains(filter)
@ -43,13 +43,12 @@ public class MongoPageRepository : MongoDbRepository<ICmsKitMongoDbContext, Page
{ {
var cancellation = GetCancellationToken(cancellationToken); var cancellation = GetCancellationToken(cancellationToken);
return await (await GetMongoQueryableAsync(cancellation)) return await (await GetQueryableAsync(cancellation))
.WhereIf<Page, IMongoQueryable<Page>>( .WhereIf(
!filter.IsNullOrWhiteSpace(), !filter.IsNullOrWhiteSpace(),
u => u.Title.ToLower().Contains(filter) || u.Slug.Contains(filter)) u => u.Title.ToLower().Contains(filter) || u.Slug.Contains(filter))
.OrderBy(sorting.IsNullOrEmpty() ? nameof(Page.Title) : sorting) .OrderBy(sorting.IsNullOrEmpty() ? nameof(Page.Title) : sorting)
.As<IMongoQueryable<Page>>() .PageBy(skipCount, maxResultCount)
.PageBy<Page, IMongoQueryable<Page>>(skipCount, maxResultCount)
.ToListAsync(cancellation); .ToListAsync(cancellation);
} }
@ -68,7 +67,7 @@ public class MongoPageRepository : MongoDbRepository<ICmsKitMongoDbContext, Page
public virtual async Task<bool> ExistsAsync([NotNull] string slug, CancellationToken cancellationToken = default) public virtual async Task<bool> ExistsAsync([NotNull] string slug, CancellationToken cancellationToken = default)
{ {
Check.NotNullOrEmpty(slug, nameof(slug)); Check.NotNullOrEmpty(slug, nameof(slug));
return await (await GetMongoQueryableAsync(cancellationToken)).AnyAsync(x => x.Slug == slug, return await (await GetQueryableAsync(cancellationToken)).AnyAsync(x => x.Slug == slug,
GetCancellationToken(cancellationToken)); GetCancellationToken(cancellationToken));
} }
@ -79,7 +78,7 @@ public class MongoPageRepository : MongoDbRepository<ICmsKitMongoDbContext, Page
public async Task<string?> FindTitleAsync(Guid pageId, CancellationToken cancellationToken = default) public async Task<string?> FindTitleAsync(Guid pageId, CancellationToken cancellationToken = default)
{ {
return await (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.Id == pageId).Select(x => x.Title) return await (await GetQueryableAsync(cancellationToken)).Where(x => x.Id == pageId).Select(x => x.Title)
.FirstOrDefaultAsync(cancellationToken); .FirstOrDefaultAsync(cancellationToken);
} }
} }

4
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Ratings/MongoRatingRepository.cs

@ -25,7 +25,7 @@ public class MongoRatingRepository : MongoDbRepository<ICmsKitMongoDbContext, Ra
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
var rating = await (await GetMongoQueryableAsync(cancellationToken)) var rating = await (await GetQueryableAsync(cancellationToken))
.FirstOrDefaultAsync(r => r.EntityType == entityType && r.EntityId == entityId && r.CreatorId == userId, .FirstOrDefaultAsync(r => r.EntityType == entityType && r.EntityId == entityId && r.CreatorId == userId,
GetCancellationToken(cancellationToken)); GetCancellationToken(cancellationToken));
@ -39,7 +39,7 @@ public class MongoRatingRepository : MongoDbRepository<ICmsKitMongoDbContext, Ra
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
var query = ( var query = (
from rating in (await GetMongoQueryableAsync(cancellationToken)) from rating in (await GetQueryableAsync(cancellationToken))
where rating.EntityType == entityType && rating.EntityId == entityId where rating.EntityType == entityType && rating.EntityId == entityId
group rating by rating.StarCount group rating by rating.StarCount
into g into g

6
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Reactions/MongoUserReactionRepository.cs

@ -29,7 +29,7 @@ public class MongoUserReactionRepository : MongoDbRepository<ICmsKitMongoDbConte
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName));
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(x => .Where(x =>
x.CreatorId == userId && x.CreatorId == userId &&
x.EntityType == entityType && x.EntityType == entityType &&
@ -47,7 +47,7 @@ public class MongoUserReactionRepository : MongoDbRepository<ICmsKitMongoDbConte
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(x => .Where(x =>
x.CreatorId == userId && x.CreatorId == userId &&
x.EntityType == entityType && x.EntityType == entityType &&
@ -63,7 +63,7 @@ public class MongoUserReactionRepository : MongoDbRepository<ICmsKitMongoDbConte
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.Where(x => .Where(x =>
x.EntityType == entityType && x.EntityType == entityType &&
x.EntityId == entityId) x.EntityId == entityId)

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

@ -67,7 +67,7 @@ public class MongoEntityTagRepository : MongoDbRepository<ICmsKitMongoDbContext,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var dbContext = await GetDbContextAsync(); var dbContext = await GetDbContextAsync();
var entityTagQueryable = await GetMongoQueryableAsync(GetCancellationToken(cancellationToken)); var entityTagQueryable = await GetQueryableAsync(GetCancellationToken(cancellationToken));
var tagQueryable = dbContext.Tags.AsQueryable(); var tagQueryable = dbContext.Tags.AsQueryable();
var resultQueryable = entityTagQueryable var resultQueryable = entityTagQueryable

17
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs

@ -29,7 +29,7 @@ public class MongoTagRepository : MongoDbRepository<ICmsKitMongoDbContext, Volo.
Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(entityType, nameof(entityType));
Check.NotNullOrEmpty(name, nameof(name)); Check.NotNullOrEmpty(name, nameof(name));
return await (await GetMongoQueryableAsync(cancellationToken)) return await (await GetQueryableAsync(cancellationToken))
.AnyAsync(x => .AnyAsync(x =>
x.EntityType == entityType && x.EntityType == entityType &&
x.Name == name, x.Name == name,
@ -69,12 +69,12 @@ public class MongoTagRepository : MongoDbRepository<ICmsKitMongoDbContext, Volo.
Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(entityType, nameof(entityType));
Check.NotNullOrEmpty(entityId, nameof(entityId)); Check.NotNullOrEmpty(entityId, nameof(entityId));
var entityTagIds = await (await GetMongoQueryableAsync<EntityTag>(cancellationToken)) var entityTagIds = await (await GetQueryableAsync<EntityTag>(cancellationToken))
.Where(q => q.EntityId == entityId) .Where(q => q.EntityId == entityId)
.Select(q => q.TagId) .Select(q => q.TagId)
.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken));
var query = (await GetMongoQueryableAsync(cancellationToken)) var query = (await GetQueryableAsync(cancellationToken))
.Where(x => .Where(x =>
x.EntityType == entityType && x.EntityType == entityType &&
entityTagIds.Contains(x.Id)); entityTagIds.Contains(x.Id));
@ -86,14 +86,14 @@ public class MongoTagRepository : MongoDbRepository<ICmsKitMongoDbContext, Volo.
public virtual async Task<List<PopularTag>> GetPopularTagsAsync(string entityType, int maxCount, CancellationToken cancellationToken = default) public virtual async Task<List<PopularTag>> GetPopularTagsAsync(string entityType, int maxCount, CancellationToken cancellationToken = default)
{ {
var tags = await (await GetMongoQueryableAsync(cancellationToken)) var tags = await (await GetQueryableAsync(cancellationToken))
.Where(x => x.EntityType == entityType) .Where(x => x.EntityType == entityType)
.Select(x => new { x.Id, x.Name }) .Select(x => new { x.Id, x.Name })
.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken));
var tagIds = tags.Select(x => x.Id); var tagIds = tags.Select(x => x.Id);
var entityTagCounts = await (await GetMongoQueryableAsync<EntityTag>(cancellationToken)) var entityTagCounts = await (await GetQueryableAsync<EntityTag>(cancellationToken))
.Where(q => tagIds.Contains(q.TagId)) .Where(q => tagIds.Contains(q.TagId))
.GroupBy(q => q.TagId) .GroupBy(q => q.TagId)
.Select(q => new { TagId = q.Key, Count = q.Count() }) .Select(q => new { TagId = q.Key, Count = q.Count() })
@ -116,8 +116,7 @@ public class MongoTagRepository : MongoDbRepository<ICmsKitMongoDbContext, Volo.
{ {
return await (await GetQueryableByFilterAsync(filter, cancellationToken)) return await (await GetQueryableByFilterAsync(filter, cancellationToken))
.OrderBy(sorting.IsNullOrEmpty() ? $"{nameof(Tag.CreationTime)}" : sorting) .OrderBy(sorting.IsNullOrEmpty() ? $"{nameof(Tag.CreationTime)}" : sorting)
.As<IMongoQueryable<Tag>>() .PageBy(skipCount, maxResultCount)
.PageBy<Tag, IMongoQueryable<Tag>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(GetCancellationToken(cancellationToken));
} }
@ -126,9 +125,9 @@ public class MongoTagRepository : MongoDbRepository<ICmsKitMongoDbContext, Volo.
return await (await GetQueryableByFilterAsync(filter, cancellationToken)).CountAsync(GetCancellationToken(cancellationToken)); return await (await GetQueryableByFilterAsync(filter, cancellationToken)).CountAsync(GetCancellationToken(cancellationToken));
} }
private async Task<IMongoQueryable<Tag>> GetQueryableByFilterAsync(string filter, CancellationToken cancellationToken = default) private async Task<IQueryable<Tag>> GetQueryableByFilterAsync(string filter, CancellationToken cancellationToken = default)
{ {
var mongoQueryable = await GetMongoQueryableAsync(cancellationToken: cancellationToken); var mongoQueryable = await GetQueryableAsync(cancellationToken: cancellationToken);
if (!filter.IsNullOrWhiteSpace()) if (!filter.IsNullOrWhiteSpace())
{ {

14
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo.CmsKit.Public.Application.Contracts.abppkg.analyze.json

@ -63,20 +63,6 @@
"contentType": "abpModule", "contentType": "abpModule",
"name": "CmsKitPublicApplicationContractsModule", "name": "CmsKitPublicApplicationContractsModule",
"summary": null "summary": null
},
{
"displayName": "Comment management",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKitPublic.Comments",
"summary": null
},
{
"displayName": "Delete all",
"isEnabled": true,
"contentType": "permission",
"name": "CmsKitPublic.Comments.DeleteAll",
"summary": null
} }
] ]
} }

41
modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo.CmsKit.Public.Application.abppkg.analyze.json

@ -69,6 +69,47 @@
"name": "CmsKitPublicApplicationModule", "name": "CmsKitPublicApplicationModule",
"summary": null "summary": null
}, },
{
"eventHandlerType": "Local",
"namespace": "Volo.CmsKit.Public.GlobalResources.Handlers",
"subscribedEvents": [
{
"underlyingType": {
"name": "GlobalResource",
"namespace": "Volo.CmsKit.GlobalResources",
"declaringAssemblyName": "Volo.CmsKit.Domain",
"fullName": "Volo.CmsKit.GlobalResources.GlobalResource"
},
"name": "EntityUpdatedEventData`1",
"namespace": "Volo.Abp.Domain.Entities.Events",
"declaringAssemblyName": "Volo.Abp.Ddd.Domain",
"fullName": "Volo.Abp.Domain.Entities.Events.EntityUpdatedEventData`1"
}
],
"implementingInterfaces": [
{
"name": "ILocalEventHandler<EntityUpdatedEventData`1>",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.ILocalEventHandler<EntityUpdatedEventData`1>"
},
{
"name": "IEventHandler",
"namespace": "Volo.Abp.EventBus",
"declaringAssemblyName": "Volo.Abp.EventBus.Abstractions",
"fullName": "Volo.Abp.EventBus.IEventHandler"
},
{
"name": "ITransientDependency",
"namespace": "Volo.Abp.DependencyInjection",
"declaringAssemblyName": "Volo.Abp.Core",
"fullName": "Volo.Abp.DependencyInjection.ITransientDependency"
}
],
"contentType": "eventHandler",
"name": "GlobalResourceEventHandler",
"summary": null
},
{ {
"namespace": "Volo.CmsKit.Public.Reactions", "namespace": "Volo.CmsKit.Public.Reactions",
"baseClass": { "baseClass": {

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

Loading…
Cancel
Save