Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into feat/volo-5292

pull/7861/head
mehmet-erim 6 years ago
parent
commit
d33c5add94
  1. 21
      docs/en/CLI.md
  2. 16
      docs/en/Tutorials/Part-2.md
  3. 23
      docs/en/Tutorials/Part-3.md
  4. 2
      docs/en/Tutorials/Part-5.md
  5. 6
      docs/en/Tutorials/Part-6.md
  6. 1
      docs/en/UI/Angular/Component-Replacement.md
  7. 288
      docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md
  8. 4
      docs/en/UI/Angular/Multi-Tenancy.md
  9. BIN
      docs/en/UI/Angular/images/my-roles-component-form-extensions.jpg
  10. BIN
      docs/en/UI/Angular/images/my-roles-component-with-extensions.jpg
  11. 21
      docs/en/docs-nav.json
  12. 7
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
  13. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj
  14. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  15. 3
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  16. 65
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs
  17. 98
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs
  18. 79
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs
  19. 38
      framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/ServiceCollectionRepositoryExtensions.cs
  20. 3
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/AbpRepositoryConventionalRegistrar.cs
  21. 2
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryRegistrarBase.cs
  22. 2
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj
  23. 59
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleExtensions.cs
  24. 60
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleExtensions.cs
  25. 42
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/Oracle/AbpEntityFrameworkCoreOracleModule.cs
  26. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs
  27. 10
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs
  28. 2
      framework/src/Volo.Abp.Minify/Volo.Abp.Minify.csproj
  29. 43
      framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs
  30. 2
      framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs
  31. 2
      framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj
  32. 5
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/RegisterDto.cs
  33. 3
      modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs
  34. 1
      modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs
  35. 1576
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201224140744_Initial.Designer.cs
  36. 1647
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201225120048_Added_Page.Designer.cs
  37. 46
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201225120048_Added_Page.cs
  38. 1643
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201228083120_Updated_Tag_Removed_HexColor.Designer.cs
  39. 24
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201228083120_Updated_Tag_Removed_HexColor.cs
  40. 1725
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201231111657_Added_Blob_Storing.Designer.cs
  41. 95
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201231111657_Added_Blob_Storing.cs
  42. 106
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.cs
  43. 73
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210210105857_Added_Media.cs
  44. 137
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219113255_Initial.Designer.cs
  45. 241
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219113255_Initial.cs
  46. 151
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219144454_BlogFeatureEnabledColumnRename.Designer.cs
  47. 23
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219144454_BlogFeatureEnabledColumnRename.cs
  48. 3907
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs
  49. 5
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Volo.CmsKit.Web.Unified.csproj
  50. 11
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogFeatureInputDto.cs
  51. 10
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogLookupDto.cs
  52. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogPostDto.cs
  53. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs
  54. 16
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogFeatureAdminAppService.cs
  55. 3
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs
  56. 24
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogPostDto.cs
  57. 15
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CmsUserDto.cs
  58. 21
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CommentDto.cs
  59. 22
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CommentGetListInput.cs
  60. 25
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CommentWithAuthorDto.cs
  61. 16
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/ICommentAdminAppService.cs
  62. 4
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs
  63. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs
  64. 4
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs
  65. 8
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs
  66. 7
      modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs
  67. 49
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs
  68. 23
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs
  69. 15
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
  70. 77
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs
  71. 4
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs
  72. 21
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs
  73. 55
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs
  74. 6
      modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs
  75. 2
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs
  76. 40
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs
  77. 4
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs
  78. 48
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs
  79. 3
      modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs
  80. 11
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/BlogFeatureDto.cs
  81. 10
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/IBlogFeatureAppService.cs
  82. 14
      modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/IBlogFeatureCacheManager.cs
  83. 25
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo.CmsKit.Common.Application.csproj
  84. 41
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureAppService.cs
  85. 46
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureCacheManager.cs
  86. 22
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureChangedHandler.cs
  87. 4
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/MediaDescriptors/MediaDescriptorAppService.cs
  88. 2
      modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs
  89. 31
      modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/Blogs/BlogFeatureController.cs
  90. 17
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogFeatureChangedEto.cs
  91. 7
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogFeatureConsts.cs
  92. 12
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs
  93. 2
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs
  94. 15
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  95. 1
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json
  96. 2
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs
  97. 12
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs
  98. 28
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogFeature.cs
  99. 67
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogFeatureManager.cs
  100. 19
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs

21
docs/en/CLI.md

@ -31,6 +31,7 @@ Here, the list of all available commands before explaining their details:
* **`update`**: Automatically updates all ABP related NuGet and NPM packages in a solution.
* **`add-package`**: Adds an ABP package to a project.
* **`add-module`**: Adds a [multi-package application module](https://docs.abp.io/en/abp/latest/Modules/Index) to a solution.
* **`list-modules`**: Lists names of open-source application modules.
* **`get-source`**: Downloads the source code of a module.
* **`generate-proxy`**: Generates client side proxies to use HTTP API endpoints.
* **`remove-proxy`**: Removes previously generated client side proxies.
@ -202,6 +203,26 @@ abp add-module ProductManagement --new --add-to-solution-file
* `--with-source-code`: Downloads the source code of the module to your solution folder and uses local project references instead of NuGet/NPM packages. This options is always `True` if `--new` is used.
* `--add-to-solution-file`: Adds the downloaded/created module to your solution file, so you will also see the projects of the module when you open the solution on a IDE. (only available when `--with-source-code` is `True`.)
### list-modules
Lists names of open-source application modules.
Usage
````bash
abp list-modules [options]
````
Example:
```bash
abp list-modules
```
#### Options
* `--include-pro-modules`: Includes commercial (pro) modules in the output.
### get-source
Downloads the source code of a module to your computer.

16
docs/en/Tutorials/Part-2.md

@ -103,7 +103,7 @@ Before starting to the UI development, we first want to prepare the localization
Localization texts are located under the `Localization/BookStore` folder of the `Acme.BookStore.Domain.Shared` project:
![bookstore-localization-files](./images/bookstore-localization-files-v2.png)
![bookstore-localization-files](images/bookstore-localization-files-v2.png)
Open the `en.json` (*the English translations*) file and change the content as below:
@ -157,7 +157,7 @@ It's time to create something visible and usable! Instead of classic MVC, we wil
Create `Books` folder under the `Pages` folder of the `Acme.BookStore.Web` project. Add a new Razor Page by right clicking the Books folder then selecting **Add > Razor Page** menu item. Name it as `Index`:
![bookstore-add-index-page](./images/bookstore-add-index-page-v2.png)
![bookstore-add-index-page](images/bookstore-add-index-page-v2.png)
Open the `Index.cshtml` and change the whole content as shown below:
@ -208,7 +208,7 @@ context.Menu.AddItem(
Run the project, login to the application with the username `admin` and the password `1q2w3E*` and see the new menu item has been added to the main menu:
![bookstore-menu-items](./images/bookstore-new-menu-item.png)
![bookstore-menu-items](images/bookstore-new-menu-item.png)
When you click to the Books menu item under the Book Store parent, you are being redirected to the new empty Books Page.
@ -250,7 +250,7 @@ Change the `Pages/Books/Index.cshtml` as following:
Create an `Index.js` file under the `Pages/Books` folder:
![bookstore-index-js-file](./images/bookstore-index-js-file-v3.png)
![bookstore-index-js-file](images/bookstore-index-js-file-v3.png)
The content of the file is shown below:
@ -344,8 +344,6 @@ It's time to create something visible and usable! There are some tools that we w
- [Ng Bootstrap](https://ng-bootstrap.github.io/#/home) will be used as the UI component library.
- [Ngx-Datatable](https://swimlane.gitbook.io/ngx-datatable/) will be used as the datatable library.
### BookModule
Run the following command line to create a new module, named `BookModule` in the root folder of the angular application:
```bash
@ -457,7 +455,7 @@ abp generate-proxy
This command will create the following files under the `/src/app/proxy/books` folder:
![Generated files](./images/generated-proxies-3.png)
![Generated files](images/generated-proxies-3.png)
### BookComponent
@ -490,7 +488,7 @@ export class BookComponent implements OnInit {
```
* We imported and injected the generated `BookService`.
* We are using the [ListService](https://docs.abp.io/en/abp/latest/UI/Angular/List-Service), a utility service of the ABP Framework which provides easy pagination, sorting and searching.
* We are using the [ListService](../UI/Angular/List-Service.md), a utility service of the ABP Framework which provides easy pagination, sorting and searching.
Open the `/src/app/book/book.component.html` and replace the content as below:
@ -531,7 +529,7 @@ Open the `/src/app/book/book.component.html` and replace the content as below:
Now you can see the final result on your browser:
![Book list final result](./images/bookstore-book-list.png)
![Book list final result](images/bookstore-book-list.png)
{{else if UI == "Blazor"}}

23
docs/en/Tutorials/Part-3.md

@ -48,13 +48,13 @@ This part is also recorded as a video tutorial and **<a href="https://www.youtub
In this section, you will learn how to create a new modal dialog form to create a new book. The modal dialog will look like in the image below:
![bookstore-create-dialog](./images/bookstore-create-dialog-2.png)
![bookstore-create-dialog](images/bookstore-create-dialog-2.png)
### Create the Modal Form
Create a new razor page, named `CreateModal.cshtml` under the `Pages/Books` folder of the `Acme.BookStore.Web` project.
![bookstore-add-create-dialog](./images/bookstore-add-create-dialog-v2.png)
![bookstore-add-create-dialog](images/bookstore-add-create-dialog-v2.png)
#### CreateModal.cshtml.cs
@ -186,7 +186,7 @@ The final content of the `Index.cshtml` is shown below:
This adds a new button called **New book** to the **top-right** of the table:
![bookstore-new-book-button](./images/bookstore-new-book-button-2.png)
![bookstore-new-book-button](images/bookstore-new-book-button-2.png)
Open the `Pages/Books/Index.js` and add the following code just after the `Datatable` configuration:
@ -281,7 +281,7 @@ Now, you can **run the application** and add some new books using the new modal
Create a new razor page, named `EditModal.cshtml` under the `Pages/Books` folder of the `Acme.BookStore.Web` project:
![bookstore-add-edit-dialog](./images/bookstore-add-edit-dialog.png)
![bookstore-add-edit-dialog](images/bookstore-add-edit-dialog.png)
### EditModal.cshtml.cs
@ -484,7 +484,7 @@ You can run the application and edit any book by selecting the edit action on a
The final UI looks as below:
![bookstore-books-table-actions](./images/bookstore-edit-button-2.png)
![bookstore-books-table-actions](images/bookstore-edit-button-2.png)
## Deleting a Book
@ -721,7 +721,7 @@ Open `/src/app/book/book.component.html` and make the following changes:
You can open your browser and click **New book** button to see the new modal.
![Empty modal for new book](./images/bookstore-empty-new-book-modal.png)
![Empty modal for new book](images/bookstore-empty-new-book-modal.png)
### Create a Reactive Form
@ -732,8 +732,7 @@ Open `/src/app/book/book.component.ts` and replace the content as below:
```js
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
// import bookTypeOptions from @proxy/books
import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
import { BookService, BookDto, bookTypeOptions } from '@proxy/books'; // add bookTypeOptions
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; // add this
@Component({
@ -959,7 +958,7 @@ export class BookComponent implements OnInit {
Now, you can open your browser to see the changes:
![Save button to the modal](./images/bookstore-new-book-form-v2.png)
![Save button to the modal](images/bookstore-new-book-form-v2.png)
## Updating a Book
@ -1087,7 +1086,7 @@ Open the `/src/app/book/book.component.html`  and add the following `ngx-datata
Added an "Actions" dropdown as the first column of the table that is shown below:
![Action buttons](./images/bookstore-actions-buttons.png)
![Action buttons](images/bookstore-actions-buttons.png)
Also, change the `ng-template #abpHeader` section as shown below:
@ -1151,11 +1150,11 @@ Open `/src/app/book/book.component.html` and modify the `ngbDropdownMenu` to add
The final actions dropdown UI looks like below:
![bookstore-final-actions-dropdown](./images/bookstore-final-actions-dropdown.png)
![bookstore-final-actions-dropdown](images/bookstore-final-actions-dropdown.png)
Clicking the "Delete" action calls the `delete` method which then shows a confirmation popup as shown below:
![bookstore-confirmation-popup](./images/bookstore-confirmation-popup.png)
![bookstore-confirmation-popup](images/bookstore-confirmation-popup.png)
{{end}}

2
docs/en/Tutorials/Part-5.md

@ -117,7 +117,7 @@ Finally, edit the localization file (`en.json` under the `Localization/BookStore
"Permission:Books.Delete": "Deleting the books"
````
> Localization key names are arbitrary and no forcing rule. But we prefer the convention used above.
> Localization key names are arbitrary and there is no forcing rule. But we prefer the convention used above.
### Permission Management UI

6
docs/en/Tutorials/Part-6.md

@ -124,7 +124,7 @@ Created this class inside the `Acme.BookStore.Domain.Shared` project since we wi
## AuthorManager: The Domain Service
`Author` constructor and `ChangeName` method is `internal`, so they can be usable only in the domain layer. Create an `AuthorManager` class in the `Authors` folder (namespace) of the `Acme.BookStore.Domain` project:
`Author` constructor and `ChangeName` methods are `internal`, so they can be used only in the domain layer. Create an `AuthorManager` class in the `Authors` folder (namespace) of the `Acme.BookStore.Domain` project:
````csharp
using System;
@ -186,7 +186,7 @@ namespace Acme.BookStore.Authors
* `AuthorManager` forces to create an author and change name of an author in a controlled way. The application layer (will be introduced later) will use these methods.
> **DDD tip**: Do not introduce domain service methods unless they are really needed and perform some core business rules. For this case, we needed to this service to be able to force the unique name constraint.
> **DDD tip**: Do not introduce domain service methods unless they are really needed and perform some core business rules. For this case, we needed this service to be able to force the unique name constraint.
Both methods checks if there is already an author with the given name and throws a special business exception, `AuthorAlreadyExistsException`, defined in the `Acme.BookStore.Domain` project (in the `Authors` folder) as shown below:
@ -226,7 +226,7 @@ This is a unique string represents the error code thrown by your application and
"BookStore:00001": "There is already an author with the same name: {name}"
````
Whenever you throw an `AuthorAlreadyExistsException`, the end use will see a this message on the UI.
Whenever you throw an `AuthorAlreadyExistsException`, the end user will see a nice error message on the UI.
## IAuthorRepository

1
docs/en/UI/Angular/Component-Replacement.md

@ -546,4 +546,5 @@ The final UI looks like below:
## See Also
- [How Replaceable Components Work with Extensions](./How-Replaceable-Components-Work-with-Extensions.md)
- [How to Replace PermissionManagementComponent](./Permission-Management-Component-Replacement.md)

288
docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md

@ -0,0 +1,288 @@
# How Replaceable Components Work with Extensions
Additional UI extensibility points ([Entity action extensions](https://docs.abp.io/en/abp/latest/UI/Angular/Entity-Action-Extensions), [data table column extensions](https://docs.abp.io/en/abp/latest/UI/Angular/Data-Table-Column-Extensions), [page toolbar extensions](https://docs.abp.io/en/abp/latest/UI/Angular/Page-Toolbar-Extensions) and others) are used in ABP pages to allow to control entity actions, table columns and page toolbar of a page. If you replace a page, you need to apply some configurations to be able to work extension components in your component. Let's see how to do this by replacing the roles page.
Create a new module called `MyRolesModule`:
```bash
yarn ng generate module my-roles --module app
```
Create a new component called `MyRolesComponent`:
```bash
yarn ng generate component my-roles/my-roles --flat --export
```
Open the generated `src/app/my-roles/my-roles.component.ts` file and replace its content with the following:
```js
import { ListService, PagedAndSortedResultRequestDto } from '@abp/ng.core';
import {
CreateRole,
DeleteRole,
eIdentityComponents,
GetRoleById,
GetRoles,
IdentityRoleDto,
IdentityState,
RolesComponent,
UpdateRole,
} from '@abp/ng.identity';
import { ePermissionManagementComponents } from '@abp/ng.permission-management';
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared';
import {
EXTENSIONS_IDENTIFIER,
FormPropData,
generateFormFromProps,
} from '@abp/ng.theme.shared/extensions';
import { Component, Injector, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { finalize, pluck } from 'rxjs/operators';
@Component({
selector: 'app-my-roles',
templateUrl: './my-roles.component.html',
providers: [
ListService,
{
provide: EXTENSIONS_IDENTIFIER,
useValue: eIdentityComponents.Roles,
},
{ provide: RolesComponent, useExisting: MyRolesComponent },
],
})
export class MyRolesComponent implements OnInit {
@Select(IdentityState.getRoles)
data$: Observable<IdentityRoleDto[]>;
@Select(IdentityState.getRolesTotalCount)
totalCount$: Observable<number>;
form: FormGroup;
selected: IdentityRoleDto;
isModalVisible: boolean;
visiblePermissions = false;
providerKey: string;
modalBusy = false;
permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
onVisiblePermissionChange = event => {
this.visiblePermissions = event;
};
constructor(
public readonly list: ListService<PagedAndSortedResultRequestDto>,
protected confirmationService: ConfirmationService,
protected store: Store,
protected injector: Injector
) {}
ngOnInit() {
this.hookToQuery();
}
buildForm() {
const data = new FormPropData(this.injector, this.selected);
this.form = generateFormFromProps(data);
}
openModal() {
this.buildForm();
this.isModalVisible = true;
}
add() {
this.selected = {} as IdentityRoleDto;
this.openModal();
}
edit(id: string) {
this.store
.dispatch(new GetRoleById(id))
.pipe(pluck('IdentityState', 'selectedRole'))
.subscribe(selectedRole => {
this.selected = selectedRole;
this.openModal();
});
}
save() {
if (!this.form.valid) return;
this.modalBusy = true;
this.store
.dispatch(
this.selected.id
? new UpdateRole({ ...this.selected, ...this.form.value, id: this.selected.id })
: new CreateRole(this.form.value)
)
.pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => {
this.isModalVisible = false;
this.list.get();
});
}
delete(id: string, name: string) {
this.confirmationService
.warn('AbpIdentity::RoleDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', {
messageLocalizationParams: [name],
})
.subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) {
this.store.dispatch(new DeleteRole(id)).subscribe(() => this.list.get());
}
});
}
private hookToQuery() {
this.list.hookToQuery(query => this.store.dispatch(new GetRoles(query))).subscribe();
}
openPermissionsModal(providerKey: string) {
this.providerKey = providerKey;
setTimeout(() => {
this.visiblePermissions = true;
}, 0);
}
sort(data) {
const { prop, dir } = data.sorts[0];
this.list.sortKey = prop;
this.list.sortOrder = dir;
}
}
```
```js
{
provide: EXTENSIONS_IDENTIFIER,
useValue: eIdentityComponents.Roles,
},
{
provide: RolesComponent,
useExisting: MyRolesComponent
}
```
The two providers we have defined in `MyRolesComponent` are required for the extension components to work correctly.
* With the first provider, we defined the extension identifier for using `RolesComponent`'s extension actions in the `MyRolesComponent`.
* With the second provider, we have replaced the `RolesComponent` injection with the `MyRolesComponent`. Default extension actions of the `RolesComponent` try to get `RolesComponent` instance. However, the actions can get the `MyRolesComponent` instance after defining the second provider.
Open the generated `src/app/my-role/my-role.component.html` file and replace its content with the following:
```html
<div id="identity-roles-wrapper" class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">My Roles</h5>
</div>
<div class="text-right col col-md-6">
<abp-page-toolbar [record]="data$ | async"></abp-page-toolbar>
</div>
</div>
</div>
<div class="card-body">
<abp-extensible-table
[data]="data$ | async"
[recordsTotal]="totalCount$ | async"
[list]="list"
></abp-extensible-table>
</div>
</div>
<abp-modal size="md" [(visible)]="isModalVisible" [busy]="modalBusy">
<ng-template #abpHeader>
<h3>{%{{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}}%}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="save()" validateOnSubmit>
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose>
{%{{{ 'AbpIdentity::Cancel' | abpLocalization }}}%}
</button>
<abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{%{{{
'AbpIdentity::Save' | abpLocalization
}}}%}</abp-button>
</ng-template>
</abp-modal>
<abp-permission-management
#abpPermissionManagement="abpPermissionManagement"
*abpReplaceableTemplate="
{
inputs: {
providerName: { value: 'R' },
providerKey: { value: providerKey },
visible: { value: visiblePermissions, twoWay: true },
hideBadges: { value: true }
},
outputs: { visibleChange: onVisiblePermissionChange },
componentKey: permissionManagementKey
};
let init = initTemplate
"
(abpInit)="init(abpPermissionManagement)"
>
</abp-permission-management>
```
We have added the `abp-page-toolbar`, `abp-extensible-table`, and `abp-extensible-form` extension components to template of the `MyRolesComponent`.
You should import the required modules for the `MyRolesComponent` to `MyRolesModule`. Open the `src/my-roles/my-roles.module.ts` file and replace the content with the following:
```js
import { UiExtensionsModule } from '@abp/ng.theme.shared/extensions';
import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { MyRolesComponent } from './my-roles.component';
import { PermissionManagementModule } from '@abp/ng.permission-management';
@NgModule({
declarations: [MyRolesComponent],
imports: [SharedModule, UiExtensionsModule, PermissionManagementModule],
exports: [MyRolesComponent],
})
export class MyRolesModule {}
```
- `UiExtensionsModule` imported to be able to use the extension components in your component.
- `PermissionManagementModule` imported to be able to use the `abp-permission-*management` in your component.
As the last step, it is needs to be replaced the `RolesComponent` with the `MyRolesComponent`. Open the `app.component.ts` and modify its content as shown below:
```js
import { ReplaceableComponentsService } from '@abp/ng.core';
import { eIdentityComponents } from '@abp/ng.identity';
import { MyRolesComponent } from './my-roles/my-roles.component';
@Component(/* component metadata */)
export class AppComponent {
constructor(private replaceableComponents: ReplaceableComponentsService) {
this.replaceableComponents.add({ component: MyRolesComponent, key: eIdentityComponents.Roles });
}
}
```
After the steps above, the `RolesComponent` has been successfully replaced with the `MyRolesComponent`. When you navigate to the `/identity/roles` URL, you will see the `MyRolesComponent`'s template and see the extension components working correctly.
![my-roles-component-with-extensions](./images/my-roles-component-with-extensions.jpg)
![my-roles-component-form-extensions](./images/my-roles-component-form-extensions.jpg)

4
docs/en/UI/Angular/Multi-Tenancy.md

@ -91,10 +91,10 @@ export const environment = {
> **Important Note:** The `application.baseUrl` and the `{0}` placeholder in the value of the `baseUrl` property are required to be able to get tenant from running URL. Other placeholders in API URLs are optional.
After the configuration above, if your app runs on the `mytenant1.mydomain.com`, the app will get tenant name as **mytenant1** and replace the environment object in `ConfigState` on app initialization as follows:
After the configuration above, if your app runs on the `mytenant1.mydomain.com`, the app will get tenant name as **mytenant1** and replace the environment object in `EnvironmentService` on app initialization as follows:
```js
// environment object in ConfigState
// environment object in EnvironmentService
{
//...

BIN
docs/en/UI/Angular/images/my-roles-component-form-extensions.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/en/UI/Angular/images/my-roles-component-with-extensions.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

21
docs/en/docs-nav.json

@ -859,6 +859,27 @@
{
"text": "Custom Setting Page",
"path": "UI/Angular/Custom-Setting-Page.md"
},
{
"text": "Extensions",
"items": [
{
"text": "Entity Action Extensions",
"path": "UI/Angular/Entity-Action-Extensions.md"
},
{
"text": "Data Table Column Extensions",
"path": "UI/Angular/Data-Table-Column-Extensions.md"
},
{
"text": "Page Toolbar Extensions",
"path": "UI/Angular/Page-Toolbar-Extensions.md"
},
{
"text": "Dynamic Form Extensions",
"path": "UI/Angular/Dynamic-Form-Extensions.md"
}
]
}
]
}

7
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor

@ -1,11 +1,14 @@
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.Extensions.Localization
@using Volo.Abp.Users
@using Volo.Abp.MultiTenancy
@using global::Localization.Resources.AbpUi
@inject ICurrentUser CurrentUser
@inject ICurrentTenant CurrentTenant
@inject IJSRuntime JsRuntime
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
@inject IStringLocalizer<AbpUiResource> UiLocalizer
<AuthorizeView>
<Authorized>
<Dropdown>
@ -28,12 +31,12 @@
}
}
<DropdownDivider />
<DropdownItem Clicked="BeginSignOut">Logout</DropdownItem>
<DropdownItem Clicked="BeginSignOut">@UiLocalizer["Logout"]</DropdownItem>
</DropdownMenu>
</Dropdown>
</Authorized>
<NotAuthorized>
<a class="nav-link" href="authentication/login">Log in</a>
<a class="nav-link" href="authentication/login">@UiLocalizer["Login"]</a>
</NotAuthorized>
</AuthorizeView>
@code{

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj

@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUglify" Version="1.11.4" />
<PackageReference Include="NUglify" Version="1.13.2" />
</ItemGroup>
<ItemGroup>

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -84,7 +84,6 @@ namespace Volo.Abp.AspNetCore.Mvc
);
var controllerModel = moduleModel.GetOrAddController(
controllerType.FullName,
_options.ControllerNameGenerator(controllerType, setting),
controllerType,
_modelOptions.IgnoredInterfaces

3
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs

@ -34,6 +34,7 @@ namespace Volo.Abp.Cli
options.Commands["update"] = typeof(UpdateCommand);
options.Commands["add-package"] = typeof(AddPackageCommand);
options.Commands["add-module"] = typeof(AddModuleCommand);
options.Commands["list-modules"] = typeof(ListModulesCommand);
options.Commands["login"] = typeof(LoginCommand);
options.Commands["logout"] = typeof(LogoutCommand);
options.Commands[GenerateProxyCommand.Name] = typeof(GenerateProxyCommand);
@ -45,7 +46,7 @@ namespace Volo.Abp.Cli
options.Commands["translate"] = typeof(TranslateCommand);
options.Commands["build"] = typeof(BuildCommand);
options.Commands["bundle"] = typeof(BundleCommand);
options.Commands["create-migration-and-run-migrator"] = typeof(CreateMigrationAndRunMigrator);
options.Commands["create-migration-and-run-migrator"] = typeof(CreateMigrationAndRunMigratorCommand);
});
}
}

65
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs

@ -1,65 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class CreateMigrationAndRunMigrator : IConsoleCommand, ITransientDependency
{
public virtual async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
if (commandLineArgs.Target.IsNullOrEmpty())
{
throw new CliUsageException(
"DbMigrations folder path is missing!"
);
}
var dbMigratorProjectPath = GetDbMigratorProjectPath(commandLineArgs.Target);
if (dbMigratorProjectPath == null)
{
throw new Exception("DbMigrator is not found!");
}
var output = CmdHelper.RunCmdAndGetOutput($"cd \"{commandLineArgs.Target}\" && dotnet ef migrations add Initial -s \"{dbMigratorProjectPath}\"");
if (output.Contains("Done.") && output.Contains("To undo this action") && output.Contains("ef migrations remove")) // Migration added successfully
{
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigratorProjectPath) + "\" && dotnet run");
}
else
{
throw new Exception("Migrations failed: " + output);
}
}
private string GetDbMigratorProjectPath(string dbMigrationsFolderPath)
{
var srcFolder = Directory.GetParent(dbMigrationsFolderPath);
var dbMigratorFolderPath = Directory.GetDirectories(srcFolder.FullName).FirstOrDefault(d => d.EndsWith(".DbMigrator"));
if (dbMigratorFolderPath == null)
{
return null;
}
return Directory.GetFiles(dbMigratorFolderPath).FirstOrDefault(f => f.EndsWith(".csproj"));
}
public string GetUsageInfo()
{
return string.Empty;
}
public string GetShortDescription()
{
return string.Empty;
}
}
}

98
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs

@ -0,0 +1,98 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class CreateMigrationAndRunMigratorCommand : IConsoleCommand, ITransientDependency
{
public ILogger<CreateMigrationAndRunMigratorCommand> Logger { get; set; }
public CreateMigrationAndRunMigratorCommand()
{
Logger = NullLogger<CreateMigrationAndRunMigratorCommand>.Instance;
}
public virtual async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
if (commandLineArgs.Target.IsNullOrEmpty())
{
throw new CliUsageException("DbMigrations folder path is missing!");
}
var dbMigratorProjectPath = GetDbMigratorProjectPath(commandLineArgs.Target);
if (dbMigratorProjectPath == null)
{
throw new Exception("DbMigrator is not found!");
}
if (!IsDotNetEfToolInstalled())
{
InstallDotnetEfTool();
}
var addMigrationCmd = $"cd \"{commandLineArgs.Target}\" && " +
$"dotnet ef migrations add Initial -s \"{dbMigratorProjectPath}\"";
var output = CmdHelper.RunCmdAndGetOutput(addMigrationCmd);
if (output.Contains("Done.") &&
output.Contains("To undo this action") &&
output.Contains("ef migrations remove"))
{
// Migration added successfully
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigratorProjectPath) + "\" && dotnet run");
await Task.CompletedTask;
}
else
{
var exceptionMsg = "Migrations failed! The following command didn't run successfully:" +
Environment.NewLine +
addMigrationCmd +
Environment.NewLine + output;
Logger.LogError(exceptionMsg);
throw new Exception(exceptionMsg);
}
}
private static bool IsDotNetEfToolInstalled()
{
var output = CmdHelper.RunCmdAndGetOutput("dotnet tool list -g");
return output.Contains("dotnet-ef");
}
private void InstallDotnetEfTool()
{
Logger.LogInformation("Installing dotnet-ef tool...");
CmdHelper.RunCmd("dotnet tool install --global dotnet-ef");
Logger.LogInformation("dotnet-ef tool is installed.");
}
private static string GetDbMigratorProjectPath(string dbMigrationsFolderPath)
{
var srcFolder = Directory.GetParent(dbMigrationsFolderPath);
var dbMigratorDirectory = Directory.GetDirectories(srcFolder.FullName)
.FirstOrDefault(d => d.EndsWith(".DbMigrator"));
return dbMigratorDirectory == null
? null
: Directory.GetFiles(dbMigratorDirectory).FirstOrDefault(f => f.EndsWith(".csproj"));
}
public string GetUsageInfo()
{
return string.Empty;
}
public string GetShortDescription()
{
return string.Empty;
}
}
}

79
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs

@ -0,0 +1,79 @@
using System;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Threading.Tasks;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class ListModulesCommand : IConsoleCommand, ITransientDependency
{
public ModuleInfoProvider ModuleInfoProvider { get; }
public ILogger<ListModulesCommand> Logger { get; set; }
public ListModulesCommand(ModuleInfoProvider moduleInfoProvider)
{
ModuleInfoProvider = moduleInfoProvider;
Logger = NullLogger<ListModulesCommand>.Instance;
}
public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
var modules = await ModuleInfoProvider.GetModuleListAsync();
var freeModules = modules.Where(m => !m.IsPro).ToList();
var proModules = modules.Where(m => m.IsPro).ToList();
var output = new StringBuilder(Environment.NewLine);
output.AppendLine("Open Source Application Modules");
output.AppendLine();
foreach (var module in freeModules)
{
output.AppendLine($"> {module.DisplayName.PadRight(50)} ({module.Name})");
}
if (commandLineArgs.Options.ContainsKey("include-pro-modules"))
{
output.AppendLine();
output.AppendLine("Commercial (Pro) Application Modules");
output.AppendLine();
foreach (var module in proModules)
{
output.AppendLine($"> {module.DisplayName.PadRight(50)} ({module.Name})");
}
}
Logger.LogInformation(output.ToString());
}
public string GetUsageInfo()
{
var sb = new StringBuilder();
sb.AppendLine("");
sb.AppendLine("'list-modules' command is used for listing open source application modules.");
sb.AppendLine("");
sb.AppendLine("Usage:");
sb.AppendLine(" abp list-modules");
sb.AppendLine(" abp list-modules --include-pro-modules");
sb.AppendLine("");
sb.AppendLine("Options:");
sb.AppendLine(" --include-pro-modules Includes commercial (pro) modules in the output.");
sb.AppendLine("");
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
return sb.ToString();
}
public string GetShortDescription()
{
return "List open source application modules";
}
}
}

38
framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/ServiceCollectionRepositoryExtensions.cs

@ -7,32 +7,36 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionRepositoryExtensions
{
public static IServiceCollection AddDefaultRepository(this IServiceCollection services, Type entityType, Type repositoryImplementationType)
public static IServiceCollection AddDefaultRepository(
this IServiceCollection services,
Type entityType,
Type repositoryImplementationType,
bool replaceExisting = false)
{
//IReadOnlyBasicRepository<TEntity>
var readOnlyBasicRepositoryInterface = typeof(IReadOnlyBasicRepository<>).MakeGenericType(entityType);
if (readOnlyBasicRepositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(readOnlyBasicRepositoryInterface, repositoryImplementationType);
RegisterService(services, readOnlyBasicRepositoryInterface, repositoryImplementationType, replaceExisting);
//IReadOnlyRepository<TEntity>
var readOnlyRepositoryInterface = typeof(IReadOnlyRepository<>).MakeGenericType(entityType);
if (readOnlyRepositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(readOnlyRepositoryInterface, repositoryImplementationType);
RegisterService(services, readOnlyRepositoryInterface, repositoryImplementationType, replaceExisting);
}
//IBasicRepository<TEntity>
var basicRepositoryInterface = typeof(IBasicRepository<>).MakeGenericType(entityType);
if (basicRepositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(basicRepositoryInterface, repositoryImplementationType);
RegisterService(services, basicRepositoryInterface, repositoryImplementationType, replaceExisting);
//IRepository<TEntity>
var repositoryInterface = typeof(IRepository<>).MakeGenericType(entityType);
if (repositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(repositoryInterface, repositoryImplementationType);
RegisterService(services, repositoryInterface, repositoryImplementationType, replaceExisting);
}
}
}
@ -44,26 +48,26 @@ namespace Microsoft.Extensions.DependencyInjection
var readOnlyBasicRepositoryInterfaceWithPk = typeof(IReadOnlyBasicRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (readOnlyBasicRepositoryInterfaceWithPk.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(readOnlyBasicRepositoryInterfaceWithPk, repositoryImplementationType);
RegisterService(services, readOnlyBasicRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting);
//IReadOnlyRepository<TEntity, TKey>
var readOnlyRepositoryInterfaceWithPk = typeof(IReadOnlyRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (readOnlyRepositoryInterfaceWithPk.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(readOnlyRepositoryInterfaceWithPk, repositoryImplementationType);
RegisterService(services, readOnlyRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting);
}
//IBasicRepository<TEntity, TKey>
var basicRepositoryInterfaceWithPk = typeof(IBasicRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (basicRepositoryInterfaceWithPk.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(basicRepositoryInterfaceWithPk, repositoryImplementationType);
RegisterService(services, basicRepositoryInterfaceWithPk, repositoryImplementationType, replaceExisting);
//IRepository<TEntity, TKey>
var repositoryInterfaceWithPk = typeof(IRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (repositoryInterfaceWithPk.IsAssignableFrom(repositoryImplementationType))
{
services.TryAddTransient(repositoryInterfaceWithPk, repositoryImplementationType);
RegisterService(services, repositoryInterfaceWithPk, repositoryImplementationType, replaceExisting);
}
}
}
@ -71,5 +75,21 @@ namespace Microsoft.Extensions.DependencyInjection
return services;
}
private static void RegisterService(
IServiceCollection services,
Type serviceType,
Type implementationType,
bool replaceExisting)
{
if (replaceExisting)
{
services.Replace(ServiceDescriptor.Transient(serviceType, implementationType));
}
else
{
services.TryAddTransient(serviceType, implementationType);
}
}
}
}

3
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/AbpRepositoryConventionalRegistrar.cs

@ -6,6 +6,9 @@ using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Domain.Repositories
{
/* Repositories are not injected by class by default.
* This class specializes repository registration to apply this rule.
*/
public class AbpRepositoryConventionalRegistrar : DefaultConventionalRegistrar
{
public static bool ExposeRepositoryClasses { get; set; }

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

@ -20,7 +20,7 @@ namespace Volo.Abp.Domain.Repositories
{
foreach (var customRepository in Options.CustomRepositories)
{
Options.Services.AddDefaultRepository(customRepository.Key, customRepository.Value);
Options.Services.AddDefaultRepository(customRepository.Key, customRepository.Value, replaceExisting: true);
}
if (Options.RegisterDefaultRepositories)

2
framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo.Abp.EntityFrameworkCore.Oracle.csproj

@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<!--<PackageReference Include="Oracle.EntityFrameworkCore" Version="3.19.80" />-->
<PackageReference Include="Oracle.EntityFrameworkCore" Version="5.21.1" />
</ItemGroup>
</Project>

59
framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextOracleExtensions.cs

@ -1,26 +1,33 @@
// using JetBrains.Annotations;
// using Microsoft.EntityFrameworkCore;
// using System;
// using Oracle.EntityFrameworkCore.Infrastructure;
// using Volo.Abp.EntityFrameworkCore.DependencyInjection;
//
// namespace Volo.Abp.EntityFrameworkCore
// {
// public static class AbpDbContextConfigurationContextOracleExtensions
// {
// public static DbContextOptionsBuilder UseOracle(
// [NotNull] this AbpDbContextConfigurationContext context,
// [CanBeNull] Action<OracleDbContextOptionsBuilder> oracleOptionsAction = null)
// {
// TODO: UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
// if (context.ExistingConnection != null)
// {
// return context.DbContextOptions.UseOracle(context.ExistingConnection, oracleOptionsAction);
// }
// else
// {
// return context.DbContextOptions.UseOracle(context.ConnectionString, oracleOptionsAction);
// }
// }
// }
// }
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using System;
using Oracle.EntityFrameworkCore.Infrastructure;
using Volo.Abp.EntityFrameworkCore.DependencyInjection;
namespace Volo.Abp.EntityFrameworkCore
{
public static class AbpDbContextConfigurationContextOracleExtensions
{
public static DbContextOptionsBuilder UseOracle(
[NotNull] this AbpDbContextConfigurationContext context,
[CanBeNull] Action<OracleDbContextOptionsBuilder> oracleOptionsAction = null)
{
if (context.ExistingConnection != null)
{
return context.DbContextOptions.UseOracle(context.ExistingConnection, optionsBuilder =>
{
optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
oracleOptionsAction?.Invoke(optionsBuilder);
});
}
else
{
return context.DbContextOptions.UseOracle(context.ConnectionString, optionsBuilder =>
{
optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
oracleOptionsAction?.Invoke(optionsBuilder);
});
}
}
}
}

60
framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsOracleExtensions.cs

@ -1,30 +1,30 @@
// using JetBrains.Annotations;
// using System;
// using Oracle.EntityFrameworkCore.Infrastructure;
//
// namespace Volo.Abp.EntityFrameworkCore
// {
// public static class AbpDbContextOptionsOracleExtensions
// {
// public static void UseOracle(
// [NotNull] this AbpDbContextOptions options,
// [CanBeNull] Action<OracleDbContextOptionsBuilder> oracleOptionsAction = null)
// {
// options.Configure(context =>
// {
// context.UseOracle(oracleOptionsAction);
// });
// }
//
// public static void UseOracle<TDbContext>(
// [NotNull] this AbpDbContextOptions options,
// [CanBeNull] Action<OracleDbContextOptionsBuilder> oracleOptionsAction = null)
// where TDbContext : AbpDbContext<TDbContext>
// {
// options.Configure<TDbContext>(context =>
// {
// context.UseOracle(oracleOptionsAction);
// });
// }
// }
// }
using JetBrains.Annotations;
using System;
using Oracle.EntityFrameworkCore.Infrastructure;
namespace Volo.Abp.EntityFrameworkCore
{
public static class AbpDbContextOptionsOracleExtensions
{
public static void UseOracle(
[NotNull] this AbpDbContextOptions options,
[CanBeNull] Action<OracleDbContextOptionsBuilder> oracleOptionsAction = null)
{
options.Configure(context =>
{
context.UseOracle(oracleOptionsAction);
});
}
public static void UseOracle<TDbContext>(
[NotNull] this AbpDbContextOptions options,
[CanBeNull] Action<OracleDbContextOptionsBuilder> oracleOptionsAction = null)
where TDbContext : AbpDbContext<TDbContext>
{
options.Configure<TDbContext>(context =>
{
context.UseOracle(oracleOptionsAction);
});
}
}
}

42
framework/src/Volo.Abp.EntityFrameworkCore.Oracle/Volo/Abp/EntityFrameworkCore/Oracle/AbpEntityFrameworkCoreOracleModule.cs

@ -1,22 +1,20 @@
// using Volo.Abp.Guids;
// using Volo.Abp.Modularity;
//
// namespace Volo.Abp.EntityFrameworkCore.Oracle
// {
// [DependsOn(
// typeof(AbpEntityFrameworkCoreModule)
// )]
// public class AbpEntityFrameworkCoreOracleModule : AbpModule
// {
// public override void ConfigureServices(ServiceConfigurationContext context)
// {
// Configure<AbpSequentialGuidGeneratorOptions>(options =>
// {
// if (options.DefaultSequentialGuidType == null)
// {
// options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
// }
// });
// }
// }
// }
using Volo.Abp.Guids;
using Volo.Abp.Modularity;
namespace Volo.Abp.EntityFrameworkCore.Oracle
{
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class AbpEntityFrameworkCoreOracleModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpSequentialGuidGeneratorOptions>(options =>
{
if (options.DefaultSequentialGuidType == null)
{
options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
}
});
}
}
}

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs

@ -43,7 +43,7 @@ namespace Volo.Abp.Http.Modeling
public ApplicationApiDescriptionModel CreateSubModel(string[] modules = null, string[] controllers = null, string[] actions = null)
{
var subModel = new ApplicationApiDescriptionModel();
var subModel = ApplicationApiDescriptionModel.Create();;
foreach (var module in Modules.Values)
{

10
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs

@ -41,17 +41,17 @@ namespace Volo.Abp.Http.Modeling
public ControllerApiDescriptionModel AddController(ControllerApiDescriptionModel controller)
{
if (Controllers.ContainsKey(controller.ControllerName))
if (Controllers.ContainsKey(controller.Type))
{
throw new AbpException($"There is already a controller with name: {controller.ControllerName} in module: {RootPath}");
throw new AbpException($"There is already a controller with type: {controller.Type} in module: {RootPath}");
}
return Controllers[controller.ControllerName] = controller;
return Controllers[controller.Type] = controller;
}
public ControllerApiDescriptionModel GetOrAddController(string uniqueName, string name, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
public ControllerApiDescriptionModel GetOrAddController(string name, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
{
return Controllers.GetOrAdd(uniqueName, () => ControllerApiDescriptionModel.Create(name, type, ignoredInterfaces));
return Controllers.GetOrAdd(type.FullName, () => ControllerApiDescriptionModel.Create(name, type, ignoredInterfaces));
}
public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions)

2
framework/src/Volo.Abp.Minify/Volo.Abp.Minify.csproj

@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUglify" Version="1.11.4" />
<PackageReference Include="NUglify" Version="1.13.2" />
</ItemGroup>
</Project>

43
framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs

@ -90,29 +90,30 @@ namespace Volo.Abp.RabbitMQ
lock (ChannelSendSyncLock)
{
QueueBindCommands.TryPeek(out var command);
switch (command.Type)
if (QueueBindCommands.TryPeek(out var command))
{
case QueueBindType.Bind:
Channel.QueueBind(
queue: Queue.QueueName,
exchange: Exchange.ExchangeName,
routingKey: command.RoutingKey
);
break;
case QueueBindType.Unbind:
Channel.QueueUnbind(
queue: Queue.QueueName,
exchange: Exchange.ExchangeName,
routingKey: command.RoutingKey
);
break;
default:
throw new AbpException($"Unknown {nameof(QueueBindType)}: {command.Type}");
switch (command.Type)
{
case QueueBindType.Bind:
Channel.QueueBind(
queue: Queue.QueueName,
exchange: Exchange.ExchangeName,
routingKey: command.RoutingKey
);
break;
case QueueBindType.Unbind:
Channel.QueueUnbind(
queue: Queue.QueueName,
exchange: Exchange.ExchangeName,
routingKey: command.RoutingKey
);
break;
default:
throw new AbpException($"Unknown {nameof(QueueBindType)}: {command.Type}");
}
QueueBindCommands.TryDequeue(out command);
}
QueueBindCommands.TryDequeue(out command);
}
}
}

2
framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs

@ -43,7 +43,7 @@ namespace Volo.Abp.Settings
return value;
}
public async Task<List<SettingValue>> GetAllAsync(string[] names)
public virtual async Task<List<SettingValue>> GetAllAsync(string[] names)
{
var result = new Dictionary<string, SettingValue>();
var settingDefinitions = SettingDefinitionManager.GetAll().Where(x => names.Contains(x.Name)).ToList();

2
framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj

@ -15,7 +15,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.0.5" />
</ItemGroup>
<ItemGroup>

5
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/RegisterDto.cs

@ -1,11 +1,12 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Auditing;
using Volo.Abp.Identity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Validation;
namespace Volo.Abp.Account
{
public class RegisterDto
public class RegisterDto : ExtensibleObject
{
[Required]
[DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxUserNameLength))]
@ -25,4 +26,4 @@ namespace Volo.Abp.Account
[Required]
public string AppName { get; set; }
}
}
}

3
modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AccountAppService.cs

@ -6,6 +6,7 @@ using Volo.Abp.Account.Localization;
using Volo.Abp.Account.Settings;
using Volo.Abp.Application.Services;
using Volo.Abp.Identity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Settings;
namespace Volo.Abp.Account
@ -42,6 +43,8 @@ namespace Volo.Abp.Account
var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.EmailAddress, CurrentTenant.Id);
input.MapExtraPropertiesTo(user);
(await UserManager.CreateAsync(user, input.Password)).CheckErrors();
await UserManager.SetEmailAsync(user,input.EmailAddress);

1
modules/cms-kit/host/Volo.CmsKit.Host.Shared/FeatureConfigurer.cs

@ -13,7 +13,6 @@ namespace Volo.CmsKit
OneTimeRunner.Run(() =>
{
GlobalFeatureManager.Instance.Modules.CmsKit().EnableAll();
GlobalFeatureManager.Instance.Modules.CmsKit().Disable<PagesFeature>();
});
}
}

1576
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201224140744_Initial.Designer.cs

File diff suppressed because it is too large

1647
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201225120048_Added_Page.Designer.cs

File diff suppressed because it is too large

46
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201225120048_Added_Page.cs

@ -1,46 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.CmsKit.Migrations
{
public partial class Added_Page : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "CmsPages",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Title = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Url = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(515)", maxLength: 515, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsPages", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_CmsPages_TenantId_Url",
table: "CmsPages",
columns: new[] { "TenantId", "Url" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CmsPages");
}
}
}

1643
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201228083120_Updated_Tag_Removed_HexColor.Designer.cs

File diff suppressed because it is too large

24
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201228083120_Updated_Tag_Removed_HexColor.cs

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

1725
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201231111657_Added_Blob_Storing.Designer.cs

File diff suppressed because it is too large

95
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201231111657_Added_Blob_Storing.cs

@ -1,95 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.CmsKit.Migrations
{
public partial class Added_Blob_Storing : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "CmsPages",
type: "nvarchar(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(515)",
oldMaxLength: 515,
oldNullable: true);
migrationBuilder.CreateTable(
name: "AbpBlobContainers",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpBlobContainers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpBlobs",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ContainerId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Content = table.Column<byte[]>(type: "varbinary(max)", maxLength: 2147483647, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpBlobs", x => x.Id);
table.ForeignKey(
name: "FK_AbpBlobs_AbpBlobContainers_ContainerId",
column: x => x.ContainerId,
principalTable: "AbpBlobContainers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AbpBlobContainers_TenantId_Name",
table: "AbpBlobContainers",
columns: new[] { "TenantId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_AbpBlobs_ContainerId",
table: "AbpBlobs",
column: "ContainerId");
migrationBuilder.CreateIndex(
name: "IX_AbpBlobs_TenantId_ContainerId_Name",
table: "AbpBlobs",
columns: new[] { "TenantId", "ContainerId", "Name" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpBlobs");
migrationBuilder.DropTable(
name: "AbpBlobContainers");
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "CmsPages",
type: "nvarchar(515)",
maxLength: 515,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(512)",
oldMaxLength: 512,
oldNullable: true);
}
}
}

106
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.cs

@ -1,106 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.CmsKit.Migrations
{
public partial class UrlSlugToSlug : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "CmsBlogPosts",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
BlogId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Title = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Slug = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
ShortDescription = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsBlogPosts", x => x.Id);
table.ForeignKey(
name: "FK_CmsBlogPosts_CmsUsers_CreatorId",
column: x => x.CreatorId,
principalTable: "CmsUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_CmsBlogPosts_CmsUsers_DeleterId",
column: x => x.DeleterId,
principalTable: "CmsUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_CmsBlogPosts_CmsUsers_LastModifierId",
column: x => x.LastModifierId,
principalTable: "CmsUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "CmsBlogs",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Slug = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsBlogs", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_CreatorId",
table: "CmsBlogPosts",
column: "CreatorId");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_DeleterId",
table: "CmsBlogPosts",
column: "DeleterId");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_LastModifierId",
table: "CmsBlogPosts",
column: "LastModifierId");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_Slug_BlogId",
table: "CmsBlogPosts",
columns: new[] { "Slug", "BlogId" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CmsBlogPosts");
migrationBuilder.DropTable(
name: "CmsBlogs");
}
}
}

73
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210210105857_Added_Media.cs

@ -1,73 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.CmsKit.Migrations
{
public partial class Added_Media : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CmsPages");
migrationBuilder.CreateTable(
name: "CmsMediaDescriptors",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: false),
MimeType = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Size = table.Column<long>(type: "bigint", maxLength: 2147483647, nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsMediaDescriptors", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CmsMediaDescriptors");
migrationBuilder.CreateTable(
name: "CmsPages",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true),
Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Title = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Url = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsPages", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_CmsPages_TenantId_Url",
table: "CmsPages",
columns: new[] { "TenantId", "Url" });
}
}
}

137
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210210105857_Added_Media.Designer.cs → modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219113255_Initial.Designer.cs

@ -11,8 +11,8 @@ using Volo.CmsKit.EntityFrameworkCore;
namespace Volo.CmsKit.Migrations
{
[DbContext(typeof(UnifiedDbContext))]
[Migration("20210210105857_Added_Media")]
partial class Added_Media
[Migration("20210219113255_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
@ -1191,6 +1191,68 @@ namespace Volo.CmsKit.Migrations
b.ToTable("CmsBlogs");
});
modelBuilder.Entity("Volo.CmsKit.Blogs.BlogFeature", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("BlogId")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<bool>("Enabled")
.HasColumnType("bit");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<string>("FeatureName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.HasKey("Id");
b.ToTable("CmsBlogFeatures");
});
modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b =>
{
b.Property<Guid>("Id")
@ -1457,6 +1519,77 @@ namespace Volo.CmsKit.Migrations
b.ToTable("CmsMediaDescriptors");
});
modelBuilder.Entity("Volo.CmsKit.Pages.Page", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Slug")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("TenantId", "Slug");
b.ToTable("CmsPages");
});
modelBuilder.Entity("Volo.CmsKit.Ratings.Rating", b =>
{
b.Property<Guid>("Id")

241
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20201224140744_Initial.cs → modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219113255_Initial.cs

@ -39,6 +39,21 @@ namespace Volo.CmsKit.Migrations
table.PrimaryKey("PK_AbpAuditLogs", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpBlobContainers",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpBlobContainers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpClaimTypes",
columns: table => new
@ -251,6 +266,52 @@ namespace Volo.CmsKit.Migrations
table.PrimaryKey("PK_AbpUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CmsBlogFeatures",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
BlogId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
FeatureName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Enabled = table.Column<bool>(type: "bit", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsBlogFeatures", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CmsBlogs",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Slug = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsBlogs", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CmsComments",
columns: table => new
@ -306,6 +367,54 @@ namespace Volo.CmsKit.Migrations
table.PrimaryKey("PK_CmsEntityTags", x => new { x.EntityId, x.TagId });
});
migrationBuilder.CreateTable(
name: "CmsMediaDescriptors",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: false),
MimeType = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Size = table.Column<long>(type: "bigint", maxLength: 2147483647, nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsMediaDescriptors", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CmsPages",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Title = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Slug = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsPages", x => x.Id);
});
migrationBuilder.CreateTable(
name: "CmsRatings",
columns: table => new
@ -328,10 +437,9 @@ namespace Volo.CmsKit.Migrations
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
EntityType = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Name = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: false),
HexColor = table.Column<string>(type: "nvarchar(6)", maxLength: 6, nullable: true),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
@ -435,6 +543,29 @@ namespace Volo.CmsKit.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AbpBlobs",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ContainerId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Content = table.Column<byte[]>(type: "varbinary(max)", maxLength: 2147483647, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpBlobs", x => x.Id);
table.ForeignKey(
name: "FK_AbpBlobs_AbpBlobContainers_ContainerId",
column: x => x.ContainerId,
principalTable: "AbpBlobContainers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AbpOrganizationUnitRoles",
columns: table => new
@ -617,6 +748,49 @@ namespace Volo.CmsKit.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CmsBlogPosts",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
BlogId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Title = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Slug = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
ShortDescription = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_CmsBlogPosts", x => x.Id);
table.ForeignKey(
name: "FK_CmsBlogPosts_CmsUsers_CreatorId",
column: x => x.CreatorId,
principalTable: "CmsUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_CmsBlogPosts_CmsUsers_DeleterId",
column: x => x.DeleterId,
principalTable: "CmsUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_CmsBlogPosts_CmsUsers_LastModifierId",
column: x => x.LastModifierId,
principalTable: "CmsUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "AbpEntityPropertyChanges",
columns: table => new
@ -660,6 +834,21 @@ namespace Volo.CmsKit.Migrations
table: "AbpAuditLogs",
columns: new[] { "TenantId", "UserId", "ExecutionTime" });
migrationBuilder.CreateIndex(
name: "IX_AbpBlobContainers_TenantId_Name",
table: "AbpBlobContainers",
columns: new[] { "TenantId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_AbpBlobs_ContainerId",
table: "AbpBlobs",
column: "ContainerId");
migrationBuilder.CreateIndex(
name: "IX_AbpBlobs_TenantId_ContainerId_Name",
table: "AbpBlobs",
columns: new[] { "TenantId", "ContainerId", "Name" });
migrationBuilder.CreateIndex(
name: "IX_AbpEntityChanges_AuditLogId",
table: "AbpEntityChanges",
@ -787,6 +976,26 @@ namespace Volo.CmsKit.Migrations
table: "AbpUsers",
column: "UserName");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_CreatorId",
table: "CmsBlogPosts",
column: "CreatorId");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_DeleterId",
table: "CmsBlogPosts",
column: "DeleterId");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_LastModifierId",
table: "CmsBlogPosts",
column: "LastModifierId");
migrationBuilder.CreateIndex(
name: "IX_CmsBlogPosts_Slug_BlogId",
table: "CmsBlogPosts",
columns: new[] { "Slug", "BlogId" });
migrationBuilder.CreateIndex(
name: "IX_CmsComments_TenantId_EntityType_EntityId",
table: "CmsComments",
@ -807,6 +1016,11 @@ namespace Volo.CmsKit.Migrations
table: "CmsEntityTags",
columns: new[] { "TenantId", "EntityId", "TagId" });
migrationBuilder.CreateIndex(
name: "IX_CmsPages_TenantId_Slug",
table: "CmsPages",
columns: new[] { "TenantId", "Slug" });
migrationBuilder.CreateIndex(
name: "IX_CmsRatings_TenantId_EntityType_EntityId_CreatorId",
table: "CmsRatings",
@ -843,6 +1057,9 @@ namespace Volo.CmsKit.Migrations
migrationBuilder.DropTable(
name: "AbpAuditLogActions");
migrationBuilder.DropTable(
name: "AbpBlobs");
migrationBuilder.DropTable(
name: "AbpClaimTypes");
@ -888,6 +1105,15 @@ namespace Volo.CmsKit.Migrations
migrationBuilder.DropTable(
name: "AbpUserTokens");
migrationBuilder.DropTable(
name: "CmsBlogFeatures");
migrationBuilder.DropTable(
name: "CmsBlogPosts");
migrationBuilder.DropTable(
name: "CmsBlogs");
migrationBuilder.DropTable(
name: "CmsComments");
@ -897,6 +1123,12 @@ namespace Volo.CmsKit.Migrations
migrationBuilder.DropTable(
name: "CmsEntityTags");
migrationBuilder.DropTable(
name: "CmsMediaDescriptors");
migrationBuilder.DropTable(
name: "CmsPages");
migrationBuilder.DropTable(
name: "CmsRatings");
@ -907,7 +1139,7 @@ namespace Volo.CmsKit.Migrations
name: "CmsUserReactions");
migrationBuilder.DropTable(
name: "CmsUsers");
name: "AbpBlobContainers");
migrationBuilder.DropTable(
name: "AbpEntityChanges");
@ -924,6 +1156,9 @@ namespace Volo.CmsKit.Migrations
migrationBuilder.DropTable(
name: "AbpUsers");
migrationBuilder.DropTable(
name: "CmsUsers");
migrationBuilder.DropTable(
name: "AbpAuditLogs");
}

151
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210209082122_UrlSlugToSlug.Designer.cs → modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219144454_BlogFeatureEnabledColumnRename.Designer.cs

@ -11,17 +11,17 @@ using Volo.CmsKit.EntityFrameworkCore;
namespace Volo.CmsKit.Migrations
{
[DbContext(typeof(UnifiedDbContext))]
[Migration("20210209082122_UrlSlugToSlug")]
partial class UrlSlugToSlug
[Migration("20210219144454_BlogFeatureEnabledColumnRename")]
partial class BlogFeatureEnabledColumnRename
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.UseIdentityColumns()
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.2");
.HasAnnotation("ProductVersion", "5.0.3")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b =>
{
@ -1191,6 +1191,68 @@ namespace Volo.CmsKit.Migrations
b.ToTable("CmsBlogs");
});
modelBuilder.Entity("Volo.CmsKit.Blogs.BlogFeature", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<Guid>("BlogId")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<string>("FeatureName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<bool>("IsEnabled")
.HasColumnType("bit");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.HasKey("Id");
b.ToTable("CmsBlogFeatures");
});
modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b =>
{
b.Property<Guid>("Id")
@ -1388,6 +1450,75 @@ namespace Volo.CmsKit.Migrations
b.ToTable("CmsContents");
});
modelBuilder.Entity("Volo.CmsKit.MediaDescriptors.MediaDescriptor", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("MimeType")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("nvarchar(255)");
b.Property<long>("Size")
.HasMaxLength(2147483647)
.HasColumnType("bigint");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("CmsMediaDescriptors");
});
modelBuilder.Entity("Volo.CmsKit.Pages.Page", b =>
{
b.Property<Guid>("Id")
@ -1438,6 +1569,11 @@ namespace Volo.CmsKit.Migrations
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Slug")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
@ -1447,14 +1583,9 @@ namespace Volo.CmsKit.Migrations
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("Url")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("TenantId", "Url");
b.HasIndex("TenantId", "Slug");
b.ToTable("CmsPages");
});

23
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210219144454_BlogFeatureEnabledColumnRename.cs

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.CmsKit.Migrations
{
public partial class BlogFeatureEnabledColumnRename : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "Enabled",
table: "CmsBlogFeatures",
newName: "IsEnabled");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "IsEnabled",
table: "CmsBlogFeatures",
newName: "Enabled");
}
}
}

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

File diff suppressed because it is too large

5
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Volo.CmsKit.Web.Unified.csproj

@ -10,7 +10,6 @@
<ItemGroup>
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="$(MicrosoftPackageVersion)" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj" />
@ -63,4 +62,8 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations" />
</ItemGroup>
</Project>

11
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogFeatureInputDto.cs

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace Volo.CmsKit.Admin.Blogs
{
public class BlogFeatureInputDto
{
[Required]
public string FeatureName { get; set; }
public bool IsEnabled { get; set; }
}
}

10
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogLookupDto.cs

@ -1,10 +0,0 @@
using System;
namespace Volo.CmsKit.Admin.Blogs
{
public class BlogLookupDto
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}

2
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateUpdateBlogPostDto.cs → modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogPostDto.cs

@ -5,7 +5,7 @@ using Volo.CmsKit.Blogs;
namespace Volo.CmsKit.Admin.Blogs
{
public class CreateUpdateBlogPostDto
public class CreateBlogPostDto
{
[Required]
public Guid BlogId { get; set; }

2
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogAdminAppService.cs

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Volo.CmsKit.Admin.Blogs

16
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogFeatureAdminAppService.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.CmsKit.Blogs;
namespace Volo.CmsKit.Admin.Blogs
{
public interface IBlogFeatureAdminAppService
{
Task SetAsync(Guid blogId, BlogFeatureInputDto dto);
Task<List<BlogFeatureDto>> GetListAsync(Guid blogId);
}
}

3
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/IBlogPostAdminAppService.cs

@ -11,7 +11,8 @@ namespace Volo.CmsKit.Admin.Blogs
BlogPostDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateBlogPostDto>
CreateBlogPostDto,
UpdateBlogPostDto>
{
Task<BlogPostDto> GetBySlugAsync(string blogSlug, string slug);

24
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogPostDto.cs

@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
using Volo.CmsKit.Blogs;
namespace Volo.CmsKit.Admin.Blogs
{
public class UpdateBlogPostDto
{
[Required]
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxTitleLength))]
public string Title { get; set; }
[Required]
[DynamicStringLength(
typeof(BlogPostConsts),
nameof(BlogPostConsts.MaxSlugLength),
nameof(BlogPostConsts.MinSlugLength))]
public string Slug { get; set; }
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))]
public string ShortDescription { get; set; }
}
}

15
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CmsUserDto.cs

@ -0,0 +1,15 @@
using System;
namespace Volo.CmsKit.Admin.Comments
{
public class CmsUserDto
{
public Guid Id { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
}

21
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CommentDto.cs

@ -0,0 +1,21 @@
using System;
namespace Volo.CmsKit.Admin.Comments
{
public class CommentDto
{
public Guid Id { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public string Text { get; set; }
public Guid? RepliedCommentId { get; set; }
public Guid CreatorId { get; set; }
public DateTime CreationTime { get; set; }
}
}

22
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CommentGetListInput.cs

@ -0,0 +1,22 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Volo.CmsKit.Admin.Comments
{
public class CommentGetListInput : PagedAndSortedResultRequestDto
{
public string EntityType { get; set; }
public string EntityId { get; set; }
public string Text { get; set; }
public Guid? RepliedCommentId { get; set; }
public string Author { get; set; }
public DateTime? CreationStartDate { get; set; }
public DateTime? CreationEndDate { get; set; }
}
}

25
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/CommentWithAuthorDto.cs

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Admin.Comments
{
public class CommentWithAuthorDto
{
public Guid Id { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public string Text { get; set; }
public Guid? RepliedCommentId { get; set; }
public Guid CreatorId { get; set; }
public DateTime CreationTime { get; set; }
public CmsUserDto Author { get; set; }
}
}

16
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Comments/ICommentAdminAppService.cs

@ -0,0 +1,16 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Volo.CmsKit.Admin.Comments
{
public interface ICommentAdminAppService : IApplicationService
{
Task<PagedResultDto<CommentWithAuthorDto>> GetListAsync(CommentGetListInput input);
Task<CommentWithAuthorDto> GetAsync(Guid id);
Task DeleteAsync(Guid id);
}
}

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

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

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

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

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

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

8
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs

@ -13,6 +13,12 @@ namespace Volo.CmsKit.Permissions
{
var cmsGroup = context.GetGroupOrNull(CmsKitAdminPermissions.GroupName) ?? context.AddGroup(CmsKitAdminPermissions.GroupName, L("Permission:CmsKit"));
if (GlobalFeatureManager.Instance.IsEnabled<CommentsFeature>())
{
var contentGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Comments.Default, L("Permission:Comments"));
contentGroup.AddChild(CmsKitAdminPermissions.Comments.Delete, L("Permission:Comments.Delete"));
}
if (GlobalFeatureManager.Instance.IsEnabled<ContentsFeature>())
{
var contentGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Contents.Default, L("Permission:Contents"));
@ -20,6 +26,7 @@ namespace Volo.CmsKit.Permissions
contentGroup.AddChild(CmsKitAdminPermissions.Contents.Update, L("Permission:Contents.Update"));
contentGroup.AddChild(CmsKitAdminPermissions.Contents.Delete, L("Permission:Contents.Delete"));
}
if (GlobalFeatureManager.Instance.IsEnabled<TagsFeature>())
{
var tagGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Tags.Default, L("Permission:TagManagement"));
@ -42,6 +49,7 @@ namespace Volo.CmsKit.Permissions
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Create, L("Permission:BlogManagement.Create"));
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Update, L("Permission:BlogManagement.Update"));
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Delete, L("Permission:BlogManagement.Delete"));
blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Features, L("Permission:BlogManagement.Features"));
var blogPostManagement = cmsGroup.AddPermission(CmsKitAdminPermissions.BlogPosts.Default, L("Permission:BlogPostManagement"));
blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Create, L("Permission:BlogPostManagement.Create"));

7
modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs

@ -6,6 +6,12 @@ namespace Volo.CmsKit.Permissions
{
public const string GroupName = "CmsKit";
public static class Comments
{
public const string Default = GroupName + ".Comments";
public const string Delete = Default + ".Delete";
}
public static class Tags
{
public const string Default = GroupName + ".Tags";
@ -36,6 +42,7 @@ namespace Volo.CmsKit.Permissions
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
public const string Features = Default + ".Features";
}
public static class BlogPosts

49
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.Admin.Blogs;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Permissions;
namespace Volo.CmsKit.Admin.Blogs
{
[RequiresGlobalFeature(typeof(BlogsFeature))]
public class BlogFeatureAdminAppService : CmsKitAdminAppServiceBase, IBlogFeatureAdminAppService
{
protected IBlogFeatureRepository BlogFeatureRepository { get; }
protected IBlogFeatureManager BlogFeatureManager { get; }
protected IDistributedEventBus EventBus { get; }
public BlogFeatureAdminAppService(
IBlogFeatureRepository blogFeatureRepository,
IBlogFeatureManager blogFeatureManager,
IDistributedEventBus eventBus)
{
BlogFeatureRepository = blogFeatureRepository;
BlogFeatureManager = blogFeatureManager;
EventBus = eventBus;
}
[Authorize(CmsKitAdminPermissions.Blogs.Features)]
public async Task<List<BlogFeatureDto>> GetListAsync(Guid blogId)
{
var blogFeatures = await BlogFeatureManager.GetListAsync(blogId);
return ObjectMapper.Map<List<BlogFeature>, List<BlogFeatureDto>>(blogFeatures);
}
[Authorize(CmsKitAdminPermissions.Blogs.Features)]
public Task SetAsync(Guid blogId, BlogFeatureInputDto dto)
{
return BlogFeatureManager.SetAsync(blogId, dto.FeatureName, dto.IsEnabled);
}
}
}

23
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs

@ -23,14 +23,15 @@ namespace Volo.CmsKit.Admin.Blogs
BlogPostDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateBlogPostDto>
CreateBlogPostDto,
UpdateBlogPostDto>
, IBlogPostAdminAppService
{
protected readonly IBlogPostManager BlogPostManager;
protected readonly IBlogPostRepository BlogPostRepository;
protected readonly IBlogRepository BlogRepository;
protected readonly IBlobContainer<BlogPostCoverImageContainer> BlobContainer;
protected readonly ICmsUserLookupService UserLookupService;
protected IBlogPostManager BlogPostManager { get; }
protected IBlogPostRepository BlogPostRepository { get; }
protected IBlogRepository BlogRepository { get; }
protected IBlobContainer<BlogPostCoverImageContainer> BlobContainer { get; }
protected ICmsUserLookupService UserLookupService { get; }
public BlogPostAdminAppService(
IRepository<BlogPost, Guid> repository,
@ -59,11 +60,11 @@ namespace Volo.CmsKit.Admin.Blogs
var blogPost = await BlogPostRepository.GetBySlugAsync(blog.Id, blogPostSlug);
return MapToGetOutputDto(blogPost);
return await MapToGetOutputDtoAsync(blogPost);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public override async Task<BlogPostDto> CreateAsync(CreateUpdateBlogPostDto input)
public override async Task<BlogPostDto> CreateAsync(CreateBlogPostDto input)
{
_ = await UserLookupService.GetByIdAsync(CurrentUser.GetId());
@ -76,11 +77,11 @@ namespace Volo.CmsKit.Admin.Blogs
input.Slug,
input.ShortDescription));
return MapToGetOutputDto(entity);
return await MapToGetOutputDtoAsync(entity);
}
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)]
public override async Task<BlogPostDto> UpdateAsync(Guid id, CreateUpdateBlogPostDto input)
public override async Task<BlogPostDto> UpdateAsync(Guid id, UpdateBlogPostDto input)
{
var blogPost = await BlogPostRepository.GetAsync(id);
@ -95,7 +96,7 @@ namespace Volo.CmsKit.Admin.Blogs
await BlogPostManager.UpdateAsync(blogPost);
return MapToGetOutputDto(blogPost);
return await MapToGetOutputDtoAsync(blogPost);
}
public virtual async Task SetCoverImageAsync(Guid id, RemoteStreamContent streamContent)

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

@ -1,14 +1,18 @@
using AutoMapper;
using Volo.Abp.AutoMapper;
using Volo.CmsKit.Admin.Blogs;
using Volo.CmsKit.Admin.Comments;
using Volo.CmsKit.Admin.Contents;
using Volo.CmsKit.Admin.MediaDescriptors;
using Volo.CmsKit.Admin.Pages;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Comments;
using Volo.CmsKit.Contents;
using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Pages;
using Volo.CmsKit.Tags;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Admin
{
@ -16,6 +20,12 @@ namespace Volo.CmsKit.Admin
{
public CmsKitAdminApplicationAutoMapperProfile()
{
CreateMap<CmsUser, Comments.CmsUserDto>();
CreateMap<Comment, CommentDto>();
CreateMap<Comment, CommentWithAuthorDto>()
.Ignore(x=> x.Author);
CreateMap<Page, PageDto>();
CreateMap<Content, ContentDto>(MemberList.Destination);
@ -24,12 +34,13 @@ namespace Volo.CmsKit.Admin
CreateMap<ContentUpdateDto, Content>(MemberList.Source);
CreateMap<BlogPost, BlogPostDto>(MemberList.Destination);
CreateMap<CreateUpdateBlogPostDto, BlogPost>(MemberList.Source);
CreateMap<CreateBlogPostDto, BlogPost>(MemberList.Source);
CreateMap<UpdateBlogPostDto, BlogPost>(MemberList.Source);
CreateMap<Blog, BlogDto>(MemberList.Destination)
.ReverseMap();
CreateMap<Blog, BlogLookupDto>(MemberList.Destination);
CreateMap<BlogFeature, BlogFeatureDto>();
CreateMap<TagEntityTypeDefiniton, TagDefinitionDto>(MemberList.Destination);

77
modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs

@ -0,0 +1,77 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Permissions;
using Volo.CmsKit.Users;
namespace Volo.CmsKit.Admin.Comments
{
[RequiresGlobalFeature(typeof(CommentsFeature))]
[Authorize(CmsKitAdminPermissions.Comments.Default)]
public class CommentAdminAppService : CmsKitAdminAppServiceBase, ICommentAdminAppService
{
protected ICommentRepository CommentRepository { get; }
public CommentAdminAppService(ICommentRepository commentRepository)
{
CommentRepository = commentRepository;
}
public virtual async Task<PagedResultDto<CommentWithAuthorDto>> GetListAsync(CommentGetListInput input)
{
var totalCount = await CommentRepository.GetCountAsync(
input.Text,
input.EntityType,
input.EntityId,
input.RepliedCommentId,
input.Author,
input.CreationStartDate,
input.CreationEndDate);
var comments = await CommentRepository.GetListAsync(
input.Text,
input.EntityType,
input.EntityId,
input.RepliedCommentId,
input.Author,
input.CreationStartDate,
input.CreationEndDate,
input.Sorting,
input.MaxResultCount,
input.SkipCount
);
var dtos = comments.Select(queryResultItem =>
{
var dto = ObjectMapper.Map<Comment, CommentWithAuthorDto>(queryResultItem.Comment);
dto.Author = ObjectMapper.Map<CmsUser, CmsUserDto>(queryResultItem.Author);
return dto;
}).ToList();
return new PagedResultDto<CommentWithAuthorDto>(totalCount, dtos);
}
public virtual async Task<CommentWithAuthorDto> GetAsync(Guid id)
{
var comment = await CommentRepository.GetWithAuthorAsync(id);
var dto = ObjectMapper.Map<Comment, CommentWithAuthorDto>(comment.Comment);
dto.Author = ObjectMapper.Map<CmsUser, CmsUserDto>(comment.Author);
return dto;
}
[Authorize(CmsKitAdminPermissions.Comments.Delete)]
public virtual async Task DeleteAsync(Guid id)
{
var comment = await CommentRepository.GetAsync(id);
await CommentRepository.DeleteWithRepliesAsync(comment);
}
}
}

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

@ -53,10 +53,10 @@ namespace Volo.CmsKit.Admin.Contents
await ContentManager.InsertAsync(entity);
return MapToGetOutputDto(entity);
return await MapToGetOutputDtoAsync(entity);
}
public async Task<ContentDto> GetAsync(
public virtual async Task<ContentDto> GetAsync(
[NotNull] string entityType,
[NotNull] string entityId)
{

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

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.GlobalFeatures;
@ -14,7 +15,7 @@ namespace Volo.CmsKit.Admin.Pages
[Authorize(CmsKitAdminPermissions.Pages.Default)]
public class PageAdminAppService : CmsKitAdminAppServiceBase, IPageAdminAppService
{
protected readonly IPageRepository PageRepository;
protected IPageRepository PageRepository { get; }
public PageAdminAppService(IPageRepository pageRepository)
{
@ -47,9 +48,9 @@ namespace Volo.CmsKit.Admin.Pages
[Authorize(CmsKitAdminPermissions.Pages.Create)]
public virtual async Task<PageDto> CreateAsync(CreatePageInputDto input)
{
await CheckPageUrlAsync(input.Url);
await CheckPageSlugAsync(input.Slug);
var page = new Page(GuidGenerator.Create(), input.Title, input.Url, input.Description, CurrentTenant?.Id);
var page = new Page(GuidGenerator.Create(), input.Title, input.Slug, input.Description, CurrentTenant?.Id);
await PageRepository.InsertAsync(page);
@ -61,13 +62,13 @@ namespace Volo.CmsKit.Admin.Pages
{
var page = await PageRepository.GetAsync(id);
if (page.Url != input.Url)
if (page.Slug != input.Slug)
{
await CheckPageUrlAsync(input.Url);
await CheckPageSlugAsync(input.Slug);
}
page.Title = input.Title;
page.Url = input.Url;
page.SetTitle(input.Title);
page.SetSlug(input.Slug);
page.Description = input.Description;
await PageRepository.UpdateAsync(page);
@ -81,11 +82,11 @@ namespace Volo.CmsKit.Admin.Pages
await PageRepository.DeleteAsync(id);
}
protected virtual async Task CheckPageUrlAsync(string url)
protected virtual async Task CheckPageSlugAsync(string slug)
{
if (await PageRepository.ExistsAsync(url))
if (await PageRepository.ExistsAsync(slug))
{
throw new PageUrlAlreadyExistException(url);
throw new PageSlugAlreadyExistsException(slug);
}
}
}

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

@ -1,19 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.Threading.Tasks;
using Volo.CmsKit.Admin.Tags;
using Volo.CmsKit.Tags;
namespace Volo.CmsKit.Admin.Tags
{
public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService
{
protected readonly ITagDefinitionStore _tagDefinitionStore;
protected readonly IEntityTagManager _entityTagManager;
protected readonly ITagManager _tagManager;
protected readonly ITagRepository _tagRepository;
protected readonly IEntityTagRepository _entityTagRepository;
protected ITagDefinitionStore TagDefinitionStore { get; }
protected IEntityTagManager EntityTagManager { get; }
protected ITagManager TagManager { get; }
protected ITagRepository TagRepository { get; }
protected IEntityTagRepository EntityTagRepository { get; }
public EntityTagAdminAppService(
ITagDefinitionStore tagDefinitionStore,
@ -22,60 +20,61 @@ namespace Volo.CmsKit.Admin.Tags
ITagRepository tagRepository,
IEntityTagRepository entityTagRepository)
{
_tagDefinitionStore = tagDefinitionStore;
_entityTagManager = entityTagManager;
_tagManager = tagManager;
_tagRepository = tagRepository;
_entityTagRepository = entityTagRepository;
TagDefinitionStore = tagDefinitionStore;
EntityTagManager = entityTagManager;
TagManager = tagManager;
TagRepository = tagRepository;
EntityTagRepository = entityTagRepository;
}
public async Task AddTagToEntityAsync(EntityTagCreateDto input)
public virtual async Task AddTagToEntityAsync(EntityTagCreateDto input)
{
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
await CheckPolicyAsync(definition.CreatePolicy);
var tag = await _tagManager.GetOrAddAsync(input.EntityType, input.TagName, CurrentTenant?.Id);
var tag = await TagManager.GetOrAddAsync(input.EntityType, input.TagName, CurrentTenant?.Id);
await _entityTagManager.AddTagToEntityAsync(
await EntityTagManager.AddTagToEntityAsync(
tag.Id,
input.EntityType,
input.EntityId,
CurrentTenant?.Id);
}
public async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input)
public virtual async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input)
{
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
await CheckPolicyAsync(definition.DeletePolicy);
await _entityTagManager.RemoveTagFromEntityAsync(
await EntityTagManager.RemoveTagFromEntityAsync(
input.TagId,
input.EntityType,
input.EntityId,
CurrentTenant?.Id);
}
public async Task SetEntityTagsAsync(EntityTagSetDto input)
public virtual async Task SetEntityTagsAsync(EntityTagSetDto input)
{
var definition = await _tagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionsAsync(input.EntityType);
await CheckPolicyAsync(definition.UpdatePolicy);
var existingTags = await _tagRepository.GetAllRelatedTagsAsync(input.EntityType, input.EntityId, CurrentTenant?.Id);
var existingTags =
await TagRepository.GetAllRelatedTagsAsync(input.EntityType, input.EntityId, CurrentTenant?.Id);
var deletedTags = existingTags.Where(x => !input.Tags.Contains(x.Name)).ToList();
var addedTags = input.Tags.Where(x => !existingTags.Any(a => a.Name == x));
await _entityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray());
await EntityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray());
foreach (var addedTag in addedTags)
{
var tag = await _tagManager.GetOrAddAsync(input.EntityType, addedTag, CurrentTenant?.Id);
var tag = await TagManager.GetOrAddAsync(input.EntityType, addedTag, CurrentTenant?.Id);
await _entityTagManager.AddTagToEntityAsync(tag.Id, input.EntityType, input.EntityId, CurrentTenant?.Id);
}
await EntityTagManager.AddTagToEntityAsync(tag.Id, input.EntityType, input.EntityId, CurrentTenant?.Id);
}
}
}
}
}

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

@ -50,7 +50,7 @@ namespace Volo.CmsKit.Admin.Tags
input.Name,
CurrentTenant?.Id);
return MapToGetOutputDto(tag);
return await MapToGetOutputDtoAsync(tag);
}
[Authorize(CmsKitAdminPermissions.Tags.Update)]
@ -60,7 +60,7 @@ namespace Volo.CmsKit.Admin.Tags
id,
input.Name);
return MapToGetOutputDto(tag);
return await MapToGetOutputDtoAsync(tag);
}
protected override IQueryable<Tag> CreateFilteredQuery(TagGetListInput input)
{
@ -72,7 +72,7 @@ namespace Volo.CmsKit.Admin.Tags
x.EntityType.ToLower().Contains(input.Filter));
}
public async Task<List<TagDefinitionDto>> GetTagDefinitionsAsync()
public virtual async Task<List<TagDefinitionDto>> GetTagDefinitionsAsync()
{
var definitions = await TagManager.GetTagDefinitionsAsync();

2
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs

@ -17,7 +17,7 @@ namespace Volo.CmsKit.Admin.Blogs
[RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)]
[Area("cms-kit")]
[Authorize(CmsKitAdminPermissions.Blogs.Default)]
[Route("api/cms-kit-admin/blogs/blogs")]
[Route("api/cms-kit-admin/blogs")]
public class BlogAdminController : CmsKitAdminController, IBlogAdminAppService
{
protected IBlogAdminAppService BlogAdminAppService { get; }

40
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs

@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Permissions;
namespace Volo.CmsKit.Admin.Blogs
{
[RequiresGlobalFeature(typeof(BlogsFeature))]
[RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)]
[Area("cms-kit")]
[Authorize(CmsKitAdminPermissions.Blogs.Features)]
[Route("api/cms-kit-admin/blogs/{blogId}/features")]
public class BlogFeatureAdminController : CmsKitAdminController, IBlogFeatureAdminAppService
{
protected IBlogFeatureAdminAppService BlogFeatureAdminAppService { get; }
public BlogFeatureAdminController(IBlogFeatureAdminAppService blogFeatureAdminAppService)
{
BlogFeatureAdminAppService = blogFeatureAdminAppService;
}
[HttpGet]
public Task<List<BlogFeatureDto>> GetListAsync(Guid blogId)
{
return BlogFeatureAdminAppService.GetListAsync(blogId);
}
[HttpPut]
public Task SetAsync(Guid blogId, BlogFeatureInputDto dto)
{
return BlogFeatureAdminAppService.SetAsync(blogId, dto);
}
}
}

4
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs

@ -31,7 +31,7 @@ namespace Volo.CmsKit.Admin.Blogs
[HttpPost]
[Authorize(CmsKitAdminPermissions.BlogPosts.Create)]
public virtual Task<BlogPostDto> CreateAsync(CreateUpdateBlogPostDto input)
public virtual Task<BlogPostDto> CreateAsync(CreateBlogPostDto input)
{
return BlogPostAdminAppService.CreateAsync(input);
}
@ -107,7 +107,7 @@ namespace Volo.CmsKit.Admin.Blogs
[HttpPut]
[Route("{id}")]
[Authorize(CmsKitAdminPermissions.BlogPosts.Update)]
public virtual Task<BlogPostDto> UpdateAsync(Guid id, CreateUpdateBlogPostDto input)
public virtual Task<BlogPostDto> UpdateAsync(Guid id, UpdateBlogPostDto input)
{
return BlogPostAdminAppService.UpdateAsync(id, input);
}

48
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs

@ -0,0 +1,48 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Permissions;
namespace Volo.CmsKit.Admin.Comments
{
[Authorize(CmsKitAdminPermissions.Comments.Default)]
[RequiresGlobalFeature(typeof(CommentsFeature))]
[RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)]
[Area("cms-kit")]
[Route("api/cms-kit-admin/comments")]
public class CommentAdminController : CmsKitAdminController, ICommentAdminAppService
{
protected ICommentAdminAppService CommentAdminAppService { get; }
public CommentAdminController(ICommentAdminAppService commentAdminAppService)
{
CommentAdminAppService = commentAdminAppService;
}
[HttpGet]
public virtual Task<PagedResultDto<CommentWithAuthorDto>> GetListAsync(CommentGetListInput input)
{
return CommentAdminAppService.GetListAsync(input);
}
[HttpGet]
[Route("{id}")]
public virtual Task<CommentWithAuthorDto> GetAsync(Guid id)
{
return CommentAdminAppService.GetAsync(id);
}
[HttpDelete]
[Route("{id}")]
[Authorize(CmsKitAdminPermissions.Comments.Delete)]
public virtual Task DeleteAsync(Guid id)
{
return CommentAdminAppService.DeleteAsync(id);
}
}
}

3
modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs

@ -1,4 +1,5 @@
using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
@ -57,7 +58,7 @@ namespace Volo.CmsKit.Admin.MediaDescriptors
var mediaDescriptorDto = await MediaDescriptorAdminAppService.CreateAsync(inputStream);
return StatusCode(201, mediaDescriptorDto);
return StatusCode((int)HttpStatusCode.Created, mediaDescriptorDto);
}
}
}

11
modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/BlogFeatureDto.cs

@ -0,0 +1,11 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureDto : EntityDto<Guid>
{
public string FeatureName { get; set; }
public bool IsEnabled { get; set; }
}
}

10
modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/IBlogFeatureAppService.cs

@ -0,0 +1,10 @@
using System;
using System.Threading.Tasks;
namespace Volo.CmsKit.Blogs
{
public interface IBlogFeatureAppService
{
Task<BlogFeatureDto> GetOrDefaultAsync(Guid blogId, string featureName);
}
}

14
modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Blogs/IBlogFeatureCacheManager.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Volo.CmsKit.Blogs
{
public interface IBlogFeatureCacheManager
{
Task<BlogFeatureDto> AddOrGetAsync(Guid blogId, string featureName, Func<Task<BlogFeatureDto>> factory);
Task ClearAsync(Guid blogId, string featureName);
}
}

25
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo.CmsKit.Common.Application.csproj

@ -1,18 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\common.props" />
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<Import Project="..\..\..\..\configureawait.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Common.Application.Contracts\Volo.CmsKit.Common.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Domain\Volo.CmsKit.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Common.Application.Contracts\Volo.CmsKit.Common.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Domain\Volo.CmsKit.Domain.csproj" />
</ItemGroup>
</Project>

41
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureAppService.cs

@ -0,0 +1,41 @@
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.EventBus.Distributed;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureAppService : CmsKitAppServiceBase, IBlogFeatureAppService
{
protected virtual IBlogFeatureRepository BlogFeatureRepository { get; }
protected virtual IBlogFeatureCacheManager BlogFeatureCacheManager { get; }
public BlogFeatureAppService(
IBlogFeatureRepository blogFeatureRepository,
IBlogFeatureCacheManager blogFeatureCacheManager)
{
BlogFeatureRepository = blogFeatureRepository;
BlogFeatureCacheManager = blogFeatureCacheManager;
}
public virtual Task<BlogFeatureDto> GetOrDefaultAsync(Guid blogId, string featureName)
{
return BlogFeatureCacheManager
.AddOrGetAsync(
blogId,
featureName,
()=> GetOrDefaultFroRepositoryAsync(blogId, featureName)
);
}
protected virtual async Task<BlogFeatureDto> GetOrDefaultFroRepositoryAsync(Guid blogId, string featureName)
{
var feature = await BlogFeatureRepository.FindAsync(blogId, featureName);
var blogFeature = feature ?? new BlogFeature(blogId, featureName);
return ObjectMapper.Map<BlogFeature, BlogFeatureDto>(blogFeature);
}
}
}

46
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureCacheManager.cs

@ -0,0 +1,46 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureCacheManager : IBlogFeatureCacheManager, ITransientDependency
{
protected IDistributedCache<BlogFeatureDto> Cache { get; }
public BlogFeatureCacheManager(IDistributedCache<BlogFeatureDto> cache)
{
Cache = cache;
}
public async Task<BlogFeatureDto> AddOrGetAsync(Guid blogId, string featureName, Func<Task<BlogFeatureDto>> factory)
{
return await Cache.GetOrAddAsync(
GetCacheKey(blogId, featureName),
factory,
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1)
});
}
public Task ClearAsync(Guid blogId, string featureName)
{
return Cache.RemoveAsync(GetCacheKey(blogId, featureName));
}
private string GetCacheKey(Guid blogId, [NotNull] string featureName)
{
Check.NotNullOrWhiteSpace(featureName, nameof(featureName));
return $"{blogId}_{featureName}";
}
}
}

22
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Blogs/BlogFeatureChangedHandler.cs

@ -0,0 +1,22 @@
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureChangedHandler : IDistributedEventHandler<BlogFeatureChangedEto>, ITransientDependency
{
protected IDistributedCache<BlogFeatureDto> Cache { get; }
public BlogFeatureChangedHandler(IDistributedCache<BlogFeatureDto> cache)
{
Cache = cache;
}
public async Task HandleEventAsync(BlogFeatureChangedEto eventData)
{
await Cache.RemoveAsync($"{eventData.BlogId}_{eventData.FeatureName}");
}
}
}

4
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/MediaDescriptors/MediaDescriptorAppService.cs

@ -10,8 +10,8 @@ namespace Volo.CmsKit.MediaDescriptors
[RequiresGlobalFeature(typeof(MediaFeature))]
public class MediaDescriptorAppService : CmsKitAppServiceBase, IMediaDescriptorAppService
{
protected readonly IMediaDescriptorRepository MediaDescriptorRepository;
protected readonly IBlobContainer<MediaContainer> MediaContainer;
protected IMediaDescriptorRepository MediaDescriptorRepository { get; }
protected IBlobContainer<MediaContainer> MediaContainer { get; }
public MediaDescriptorAppService(IMediaDescriptorRepository mediaDescriptorRepository, IBlobContainer<MediaContainer> mediaContainer)
{

2
modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/Tags/TagAppService.cs

@ -9,7 +9,7 @@ namespace Volo.CmsKit.Tags
{
public class TagAppService : CmsKitAppServiceBase, ITagAppService
{
protected readonly ITagRepository TagRepository;
protected ITagRepository TagRepository { get; }
public TagAppService(ITagRepository tagRepository)
{

31
modules/cms-kit/src/Volo.CmsKit.Common.HttpApi/Volo/CmsKit/Blogs/BlogFeatureController.cs

@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.GlobalFeatures;
namespace Volo.CmsKit.Blogs
{
[RequiresGlobalFeature(typeof(BlogsFeature))]
[RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)]
[Area("cms-kit")]
[Route("api/cms-kit/blogs/{blogId}/features")]
public class BlogFeatureController : CmsKitControllerBase, IBlogFeatureAppService
{
protected IBlogFeatureAppService BlogFeatureAppService { get; }
public BlogFeatureController(IBlogFeatureAppService blogFeatureAppService)
{
BlogFeatureAppService = blogFeatureAppService;
}
[HttpGet]
[Route("{featureName}")]
public Task<BlogFeatureDto> GetOrDefaultAsync(Guid blogId, string featureName)
{
return BlogFeatureAppService.GetOrDefaultAsync(blogId, featureName);
}
}
}

17
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogFeatureChangedEto.cs

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.EventBus;
namespace Volo.CmsKit.Blogs
{
[EventName("CmsKit.Blogs.BlogFeature.Changed")]
public class BlogFeatureChangedEto
{
public Guid BlogId { get; set; }
public string FeatureName { get; set; }
public bool IsEnabled { get; set; }
}
}

7
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogFeatureConsts.cs

@ -0,0 +1,7 @@
namespace Volo.CmsKit.Blogs
{
public static class BlogFeatureConsts
{
public const int MaxFeatureNameLenth = 64;
}
}

12
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs

@ -1,4 +1,6 @@
namespace Volo.CmsKit.Blogs
using Volo.CmsKit.GlobalFeatures;
namespace Volo.CmsKit.Blogs
{
public static class BlogPostConsts
{
@ -11,5 +13,13 @@
public static int MaxShortDescriptionLength { get; set; } = 256;
public const string EntityType = "BlogPost";
public const string CommentsFeatureName = CommentsFeature.Name;
public const string ReactionsFeatureName = ReactionsFeature.Name;
public const string RatingsFeatureName = RatingsFeature.Name;
public const string TagsFeatureName = TagsFeature.Name;
}
}

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

@ -12,7 +12,7 @@
public static class Pages
{
public const string UrlAlreadyExist = "CmsKit:Page:0001";
public const string SlugAlreadyExist = "CmsKit:Page:0001";
}
public static class Blogs

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

@ -3,7 +3,8 @@
"texts": {
"CmsKit:0002": "Content already exists!",
"CmsKit:0003": "The entity {0} is not taggable.",
"CmsKit:BlogPost:0001": "Same url slug already exists!",
"CmsKit:BlogPost:0001": "The given slug already exists!",
"CmsKit:Media:0001": "'{Name}' is not a valid media name.",
"CmsKit:Page:0001": "The given url ({0}) already exists.",
"CmsKit:Tag:0002": "The entity is not taggable!",
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
@ -16,11 +17,17 @@
"LoginToReply": "Login to reply",
"Menu:CMS": "CMS",
"MessageDeletionConfirmationMessage": "This comment will be deleted completely.",
"Permission:BlogManagement.Features": "Features",
"Permission:CmsKit": "CmsKit",
"Permission:Comments": "Comment Management",
"Permission:Comments.Delete": "Delete",
"Permission:Contents": "Content Management",
"Permission:Contents.Create": "Create Content",
"Permission:Contents.Delete": "Delete Content",
"Permission:Contents.Update": "Update Content",
"Permission:MediaDescriptorManagement": "Media Management",
"Permission:MediaDescriptorManagement:Create": "Create",
"Permission:MediaDescriptorManagement:Delete": "Delete",
"Permission:PageManagement": "Page Management",
"Permission:PageManagement:Create": "Create",
"Permission:PageManagement:Delete": "Delete",
@ -40,10 +47,6 @@
"Undo": "Undo",
"Update": "Update",
"YourComment": "Your comment",
"YourReply": "Your reply",
"CmsKit:Media:0001": "'{Name}' is not a valid media name.",
"Permission:MediaDescriptorManagement": "Media Management",
"Permission:MediaDescriptorManagement:Create": "Create",
"Permission:MediaDescriptorManagement:Delete": "Delete"
"YourReply": "Your reply"
}
}

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

@ -16,6 +16,7 @@
"LoginToReply": "Cevap vermek için giriş yap",
"Menu:CMS": "CMS",
"MessageDeletionConfirmationMessage": "Bu yorum tamamen silinecektir",
"Permission:BlogManagement.Features": "Özellikler",
"Permission:CmsKit": "CmsKit",
"Permission:Contents": "İçerik Yönetimi",
"Permission:Contents.Create": "İçerik Oluşturma",

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

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

12
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/Blog.cs

@ -20,18 +20,20 @@ namespace Volo.CmsKit.Blogs
TenantId = tenantId;
}
public string Name { get; protected set; }
[NotNull]
public virtual string Name { get; protected set; }
public string Slug { get; protected set; }
[NotNull]
public virtual string Slug { get; protected set; }
public Guid? TenantId { get; protected set; }
public virtual Guid? TenantId { get; protected set; }
public void SetName(string name)
public virtual void SetName(string name)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name), maxLength: BlogConsts.MaxNameLength);
}
public void SetSlug(string slug)
public virtual void SetSlug(string slug)
{
Check.NotNullOrWhiteSpace(slug, nameof(slug), maxLength: BlogConsts.MaxNameLength);

28
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogFeature.cs

@ -0,0 +1,28 @@
using JetBrains.Annotations;
using System;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
namespace Volo.CmsKit.Blogs
{
public class BlogFeature : FullAuditedAggregateRoot<Guid>, IEquatable<BlogFeature>
{
public Guid BlogId { get; protected set; }
public string FeatureName { get; protected set; }
public bool IsEnabled { get; set; } = true;
public BlogFeature(Guid blogId, [NotNull] string featureName, bool isEnabled = true)
{
BlogId = blogId;
FeatureName = Check.NotNullOrWhiteSpace(featureName, nameof(featureName));
IsEnabled = isEnabled;
}
public bool Equals(BlogFeature other)
{
return BlogId == other?.BlogId && FeatureName == other?.FeatureName;
}
}
}

67
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogFeatureManager.cs

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Uow;
namespace Volo.CmsKit.Blogs
{
public class BlogFeatureManager : DomainService, IBlogFeatureManager
{
protected IBlogFeatureRepository BlogFeatureRepository { get; }
protected IDefaultBlogFeatureProvider DefaultBlogFeatureProvider { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IDistributedEventBus EventBus { get; }
public BlogFeatureManager(
IBlogFeatureRepository blogFeatureRepository,
IDefaultBlogFeatureProvider defaultBlogFeatureProvider,
IUnitOfWorkManager unitOfWorkManager,
IDistributedEventBus eventBus)
{
BlogFeatureRepository = blogFeatureRepository;
DefaultBlogFeatureProvider = defaultBlogFeatureProvider;
UnitOfWorkManager = unitOfWorkManager;
EventBus = eventBus;
}
public async Task<List<BlogFeature>> GetListAsync(Guid blogId)
{
var blogFeatures = await BlogFeatureRepository.GetListAsync(blogId);
var defaultFeatures = await DefaultBlogFeatureProvider.GetDefaultFeaturesAsync(blogId);
defaultFeatures.ForEach(x => blogFeatures.AddIfNotContains(x));
return blogFeatures;
}
public async Task SetAsync(Guid blogId, string featureName, bool isEnabled)
{
var blogFeature = await BlogFeatureRepository.FindAsync(blogId, featureName);
if (blogFeature == null)
{
var newBlogFeature = new BlogFeature(blogId, featureName, isEnabled);
await BlogFeatureRepository.InsertAsync(newBlogFeature);
}
else
{
blogFeature.IsEnabled = isEnabled;
await BlogFeatureRepository.UpdateAsync(blogFeature);
}
await UnitOfWorkManager.Current.SaveChangesAsync();
await EventBus.PublishAsync(new BlogFeatureChangedEto
{
BlogId = blogId,
FeatureName = featureName,
IsEnabled = isEnabled
});
}
}
}

19
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs

@ -1,10 +1,8 @@
using JetBrains.Annotations;
using System;
using System.Text.RegularExpressions;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
using Volo.CmsKit.Blogs;
using Volo.CmsKit.Blogs.Extensions;
using Volo.CmsKit.Users;
@ -12,15 +10,18 @@ namespace Volo.CmsKit.Blogs
{
public class BlogPost : FullAuditedAggregateRootWithUser<Guid, CmsUser>, IMultiTenant
{
public Guid BlogId { get; protected set; }
public virtual Guid BlogId { get; protected set; }
public string Title { get; protected set; }
[NotNull]
public virtual string Title { get; protected set; }
public string Slug { get; protected set; }
[NotNull]
public virtual string Slug { get; protected set; }
public string ShortDescription { get; protected set; }
[NotNull]
public virtual string ShortDescription { get; protected set; }
public Guid? TenantId { get; protected set; }
public virtual Guid? TenantId { get; protected set; }
protected BlogPost()
{
@ -39,7 +40,7 @@ namespace Volo.CmsKit.Blogs
ShortDescription = shortDescription;
}
public void SetTitle(string title)
public virtual void SetTitle(string title)
{
Title = Check.NotNullOrWhiteSpace(title, nameof(title), BlogPostConsts.MaxTitleLength);
}
@ -51,7 +52,7 @@ namespace Volo.CmsKit.Blogs
Slug = slug.NormalizeSlug();
}
public void SetShortDescription(string shortDescription)
public virtual void SetShortDescription(string shortDescription)
{
ShortDescription = Check.Length(shortDescription, nameof(shortDescription), BlogPostConsts.MaxShortDescriptionLength);
}

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

Loading…
Cancel
Save