Browse Source

new feature(CmsKit): Marked Item

Add Marked Item feature to allow marking items as  favorite, starred, flagged, or bookmarked.

- Added Marked Toggling Component to mark items via pre-defined icons/emojis.
- Created Marked Item widget for toggling marks on items.

Documentation: Provided detailed usage and configuration instructions in the CMS Kit Module documentation.
pull/20056/head
Suhaib 2 years ago
parent
commit
21d5582123
  1. 1
      docs/en/Modules/Cms-Kit/Index.md
  2. 148
      docs/en/Modules/Cms-Kit/MarkedItems.md
  3. BIN
      docs/en/images/cmskit-module-markedItems.png
  4. BIN
      docs/en/images/cmskit-module-markedItemsFilter.gif
  5. 11
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs
  6. 30
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml
  7. 4
      modules/cms-kit/src/Volo.CmsKit.Common.Web/CmsKitUiOptions.cs
  8. 21
      modules/cms-kit/src/Volo.CmsKit.Common.Web/Icons/IconDictionaryHelper.cs
  9. 18
      modules/cms-kit/src/Volo.CmsKit.Common.Web/Icons/LocalizableIconDictionaryBase.cs
  10. 7
      modules/cms-kit/src/Volo.CmsKit.Common.Web/MarkedItems/MarkedItemIconDictionary.cs
  11. 16
      modules/cms-kit/src/Volo.CmsKit.Common.Web/Reactions/ReactionIconDictionary.cs
  12. 5
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs
  13. 9
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs
  14. 1
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs
  15. 3
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs
  16. 27
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/MarkedItemsFeature.cs
  17. 8
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json
  18. 500
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json
  19. 9
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MarkedItems/StandardMarkedItems.cs
  20. 9
      modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MarkedItems/UserMarkedItemConsts.cs
  21. 10
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/CmsKitMarkedItemOptions.cs
  22. 36
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/DefaultMarkedItemDefinitionStore.cs
  23. 16
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/EntityCannotBeMarkedException.cs
  24. 8
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/IMarkedItemDefinitionStore.cs
  25. 31
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/IUserMarkedItemRepository.cs
  26. 16
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/MarkedItemEntityTypeDefinition.cs
  27. 58
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/MarkedItemManager.cs
  28. 36
      modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/UserMarkedItem.cs
  29. 2
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs
  30. 23
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs
  31. 2
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs
  32. 2
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs
  33. 67
      modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/MarkedItems/EfCoreUserMarkedItemRepository.cs
  34. 3
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs
  35. 6
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs
  36. 3
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs
  37. 3
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs
  38. 67
      modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/MarkedItems/MongoUserMarkedItemRepository.cs
  39. 10
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/MarkedItems/IMarkedItemPublicAppService.cs
  40. 11
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/MarkedItems/MarkedItemDto.cs
  41. 11
      modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/MarkedItems/MarkedItemWithToggleDto.cs
  42. 69
      modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicAppService.cs
  43. 15
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs
  44. 17
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Blogs/BlogPostGetListInput.cs
  45. 28
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs
  46. 21
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CmsUserDto.cs
  47. 33
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CommentDto.cs
  48. 31
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CommentWithDetailsDto.cs
  49. 25
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CreateCommentInput.cs
  50. 22
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/ICommentPublicAppService.cs
  51. 21
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/UpdateCommentInput.cs
  52. 17
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs
  53. 18
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/GlobalResources/IGlobalResourcePublicAppService.cs
  54. 18
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/IMarkedItemPublicAppService.cs
  55. 15
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemDto.cs
  56. 37
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicClientProxy.Generated.cs
  57. 7
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicClientProxy.cs
  58. 17
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemWithToggleDto.cs
  59. 17
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Menus/IMenuItemPublicAppService.cs
  60. 21
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Pages/IPagePublicAppService.cs
  61. 15
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/CreateUpdateRatingInput.cs
  62. 20
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/IRatingPublicAppService.cs
  63. 25
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/RatingDto.cs
  64. 19
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/RatingWithStarCountDto.cs
  65. 20
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Reactions/IReactionPublicAppService.cs
  66. 17
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Reactions/ReactionDto.cs
  67. 19
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Reactions/ReactionWithSelectionDto.cs
  68. 18
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Tags/ITagAppService.cs
  69. 8838
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json
  70. 38
      modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicController.cs
  71. 10
      modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs
  72. 6
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs
  73. 14
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/Default.cshtml
  74. 13
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/MarkedItemToggleScriptBundleContributor.cs
  75. 12
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/MarkedItemToggleStyleBundleContributor.cs
  76. 77
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/MarkedItemToggleViewComponent.cs
  77. 7
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/default.css
  78. 92
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/default.js
  79. 22
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Modals/Login/LoginModal.cshtml
  80. 32
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Modals/Login/LoginModal.cshtml.cs
  81. 22
      modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js
  82. 65
      modules/cms-kit/test/Volo.CmsKit.Application.Tests/MarkedItems/MarkedItemPublicAppService_Tests.cs
  83. 45
      modules/cms-kit/test/Volo.CmsKit.Domain.Tests/MarkedItems/MarkedItemManager_Tests.cs
  84. 6
      modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/MarkedItems/UserMarkedItemRepository_Tests.cs
  85. 9
      modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/MarkedItems/UserMarkedItemRepository_Tests.cs
  86. 28
      modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs
  87. 64
      modules/cms-kit/test/Volo.CmsKit.TestBase/MarkedItems/UserMarkedItemRepository_Tests.cs

1
docs/en/Modules/Cms-Kit/Index.md

@ -17,6 +17,7 @@ The following features are currently available:
* Provides a [**menu**](Menus.md) system to manage public menus dynamically. * Provides a [**menu**](Menus.md) system to manage public menus dynamically.
* Provides a [**global resources**](Global-Resources.md) system to add global styles and scripts dynamically. * Provides a [**global resources**](Global-Resources.md) system to add global styles and scripts dynamically.
* Provides a [**Dynamic Widget**](Dynamic-Widget.md) system to create dynamic widgets for page and blog posts. * Provides a [**Dynamic Widget**](Dynamic-Widget.md) system to create dynamic widgets for page and blog posts.
* Provides a [**Marked Item**](MarkedItems.md) system to mark any kind of resource, like a blog post or a product, as a favorite, starred, flagged, or bookmarked.
> You can click on the any feature links above to understand and learn how to use it. > You can click on the any feature links above to understand and learn how to use it.

148
docs/en/Modules/Cms-Kit/MarkedItems.md

@ -0,0 +1,148 @@
# Marked Item System
CMS kit provides a marking system to mark any kind of resource, like a blog post or a product, as a favorite, starred, flagged, or bookmarked.
Marked toggling component allows users to mark your items via pre-defined icons/emojis. Here how the marked toggling components may look like:
![markedItems](../../images/cmskit-module-markedItems.png)
you can also customize the marking icons shown in the toggling components.
## Enabling the Marked Item Feature
By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime.
> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time.
## Options
Marking system provides a simple approach to define your entity type with mark types like favorite or starred. For example, if you want to use the marking system for products, you need to define an entity type named `product` with the icon name.
`CmsKitMarkedItemOptions` can be configured in YourModule.cs, in the `ConfigureServices` method of your [module](https://docs.abp.io/en/abp/latest/Module-Development-Basics). Example:
```csharp
Configure<CmsKitMarkedItemOptions>(options =>
{
options.EntityTypes.Add(
new MarkedItemEntityTypeDefinition(
"product",
StandardMarkedItems.Favorite
)
);
});
```
`CmsKitMarkedItemOptions` properties:
- `EntityTypes`: List of defined entity types (`CmsKitMarkedItemOptions`) in the marking system.
`MarkedItemEntityTypeDefinition` properties:
- `EntityType`: Name of the entity type.
- `IconName`: The name of the icon.
## The Marked Item widget
The marking system provides a toggle widget to allow users to add/remove the marks from an item. You can place the widget with the item as shown below:
``` csharp
@await Component.InvokeAsync(typeof (MarkedItemToggleViewComponent), new
{
entityId = "...",
entityType = "product",
needsConfirmation = true // (optional)
})
```
* `entityType` was explained in the previous section.
* `entityId` should be the unique id of the product, in this example. If you have a Product entity, you can use its Id here.
* `needsConfirmation` An optional parameter to let the user confirm when removing the mark.
# Filter on marked items
Filtering on marked items enhances the user experience by making it easier to search marked items.
![markedItemsFilter](../../images/cmskit-module-markedItemsFilter.gif)
There is an ability to utilize the marking system to let users filter on their marked items. The code below shows how you can filter on your query filter:
```csharp
protected async override Task<IQueryable<YourEntity>> CreateFilteredQueryAsync(YourEntityPagedAndSortedResultDto input)
{
IQueryable<YourEntity> query = await base.CreateFilteredQueryAsync(input);
if (input.FilterOnFavorites && CurrentUser.IsAuthenticated)
{
var markedQuery = await UserMarkedItemRepository.GetQueryForUserAsync("entityType", CurrentUser.GetId());
query = query.Where(e => markedQuery.Any(m => m.EntityId == e.Id));
}
// ...
return query;
}
```
# Internals
## Domain Layer
#### Aggregates
This module follows the [Entity Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Entities) guide.
##### UserMarkedItem
A user markedItem represents a user has marking on the item.
- `UserMarkedItem` (aggregate root): Represents a marked item in the system.
#### Repositories
This module follows the [Repository Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories) guide.
Following custom repositories are defined for this feature:
- `IUserMarkedItemRepository`
#### Domain services
This module follows the [Domain Services Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services) guide.
##### Marked Item Manager
`MarkedItemManager` is used to perform some operations for the `UserMarkedItem` aggregate root.
### Application layer
#### Application services
- `MarkedItemPublicAppService` (implements `IMarkedItemPublicAppService`): Implements the use cases of marking system.
### Database providers
#### Common
##### Table / collection prefix & schema
All tables/collections use the `Cms` prefix by default. Set static properties on the `CmsKitDbProperties` class if you need to change the table prefix or set a schema name (if supported by your database provider).
##### Connection string
This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string.
See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details.
#### Entity Framework Core
##### Tables
- CmsUserMarkedItems
#### MongoDB
##### Collections
- **CmsUserMarkedItems**

BIN
docs/en/images/cmskit-module-markedItems.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
docs/en/images/cmskit-module-markedItemsFilter.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

11
modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs

@ -42,6 +42,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.CmsKit.Public.Pages; using Volo.CmsKit.Public.Pages;
using Volo.CmsKit.MarkedItems;
#if EntityFrameworkCore #if EntityFrameworkCore
@ -234,6 +235,16 @@ public class CmsKitWebUnifiedModule : AbpModule
{ {
options.EntityTypes.Add(new RatingEntityTypeDefinition("quote")); options.EntityTypes.Add(new RatingEntityTypeDefinition("quote"));
}); });
Configure<CmsKitMarkedItemOptions>(options =>
{
options.EntityTypes.Add(
new MarkedItemEntityTypeDefinition(
"product",
StandardMarkedItems.Favorite
)
);
});
} }
public override void OnApplicationInitialization(ApplicationInitializationContext context) public override void OnApplicationInitialization(ApplicationInitializationContext context)

30
modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml

@ -8,6 +8,7 @@
@using Volo.CmsKit.GlobalFeatures @using Volo.CmsKit.GlobalFeatures
@using Volo.CmsKit.Pages @using Volo.CmsKit.Pages
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.MarkedItemToggle
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection
@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Tags @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Tags
@ -118,3 +119,32 @@
} }
</abp-column> </abp-column>
</abp-row> </abp-row>
<hr />
<abp-row>
@for (int i = 1; i <= 4; i++)
{
var name = $"Item {i}";
<abp-column>
<abp-card background="Light" text-color="Dark" border="Success" class="mb-3" style="max-width: 18rem;">
<abp-card-header class="d-flex justify-content-between">
<div>
Item
</div>
<div>
@await Component.InvokeAsync(typeof(MarkedItemToggleViewComponent), new
{
entityId = name,
entityType = "product",
needsConfirmation = true // (optional)
})
</div>
</abp-card-header>
<abp-card-body>
<abp-card-title>@name</abp-card-title>
</abp-card-body>
</abp-card>
</abp-column>
}
</abp-row>

4
modules/cms-kit/src/Volo.CmsKit.Common.Web/CmsKitUiOptions.cs

@ -1,4 +1,5 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using Volo.CmsKit.Web.MarkedItems;
using Volo.CmsKit.Web.Reactions; using Volo.CmsKit.Web.Reactions;
namespace Volo.CmsKit.Web; namespace Volo.CmsKit.Web;
@ -10,9 +11,12 @@ public class CmsKitUiOptions
public CmsKitUiCommentOptions CommentsOptions { get; } public CmsKitUiCommentOptions CommentsOptions { get; }
public MarkedItemIconDictionary MarkedItemIcons { get; }
public CmsKitUiOptions() public CmsKitUiOptions()
{ {
ReactionIcons = new ReactionIconDictionary(); ReactionIcons = new ReactionIconDictionary();
CommentsOptions = new CmsKitUiCommentOptions(); CommentsOptions = new CmsKitUiCommentOptions();
MarkedItemIcons = new MarkedItemIconDictionary();
} }
} }

21
modules/cms-kit/src/Volo.CmsKit.Common.Web/Icons/IconDictionaryHelper.cs

@ -0,0 +1,21 @@
using System.Collections.Generic;
using Volo.Abp;
namespace Volo.CmsKit.Web.Icons;
public static class IconDictionaryHelper
{
public static string GetLocalizedIcon(
Dictionary<string, LocalizableIconDictionary> dictionary,
string name,
string cultureName = null)
{
var icon = dictionary.GetOrDefault(name);
if (icon == null)
{
throw new AbpException($"No icon defined for the item with name '{name}'");
}
return icon.GetLocalizedIconOrDefault(cultureName);
}
}

18
modules/cms-kit/src/Volo.CmsKit.Common.Web/Icons/LocalizableIconDictionaryBase.cs

@ -0,0 +1,18 @@
using System.Collections.Generic;
using Volo.Abp;
namespace Volo.CmsKit.Web.Icons;
public class LocalizableIconDictionaryBase : Dictionary<string, LocalizableIconDictionary>
{
public string GetLocalizedIcon(string name, string cultureName = null)
{
var icon = this.GetOrDefault(name);
if (icon == null)
{
throw new AbpException($"No icon defined for the item with name '{name}'");
}
return icon.GetLocalizedIconOrDefault(cultureName);
}
}

7
modules/cms-kit/src/Volo.CmsKit.Common.Web/MarkedItems/MarkedItemIconDictionary.cs

@ -0,0 +1,7 @@
using Volo.CmsKit.Web.Icons;
namespace Volo.CmsKit.Web.MarkedItems;
public class MarkedItemIconDictionary : LocalizableIconDictionaryBase
{
}

16
modules/cms-kit/src/Volo.CmsKit.Common.Web/Reactions/ReactionIconDictionary.cs

@ -1,19 +1,7 @@
using System.Collections.Generic; using Volo.CmsKit.Web.Icons;
using Volo.Abp;
using Volo.CmsKit.Web.Icons;
namespace Volo.CmsKit.Web.Reactions; namespace Volo.CmsKit.Web.Reactions;
public class ReactionIconDictionary : Dictionary<string, LocalizableIconDictionary> public class ReactionIconDictionary : LocalizableIconDictionaryBase
{ {
public string GetLocalizedIcon(string name, string cultureName = null)
{
var icon = this.GetOrDefault(name);
if (icon == null)
{
throw new AbpException($"No icon defined for the reaction with name '{name}'");
}
return icon.GetLocalizedIconOrDefault(cultureName);
}
} }

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

@ -44,4 +44,9 @@ public static class CmsKitErrorCodes
public const string InvalidName = "CmsKit:Media:0001"; public const string InvalidName = "CmsKit:Media:0001";
public const string EntityTypeDoesntExist = "CmsKit:Media:0002"; public const string EntityTypeDoesntExist = "CmsKit:Media:0002";
} }
public static class MarkedItems
{
public const string EntityCannotBeMarked = "CmsKit:MarkedItem:0001";
}
} }

9
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs

@ -84,6 +84,15 @@ public class CmsKitFeatureDefinitionProvider : FeatureDefinitionProvider
L("Feature:TagEnableDescription"), L("Feature:TagEnableDescription"),
new ToggleStringValueType()); new ToggleStringValueType());
} }
if (GlobalFeatureManager.Instance.IsEnabled<MarkedItemsFeature>())
{
group.AddFeature(CmsKitFeatures.MarkedItemEnable,
"true",
L("Feature:MarkedItemEnable"),
L("Feature:MarkedItemEnableDescription"),
new ToggleStringValueType());
}
} }
private static LocalizableString L(string name) private static LocalizableString L(string name)

1
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs

@ -11,4 +11,5 @@ public static class CmsKitFeatures
public const string RatingEnable = GroupName + ".RatingEnable"; public const string RatingEnable = GroupName + ".RatingEnable";
public const string ReactionEnable = GroupName + ".ReactionEnable"; public const string ReactionEnable = GroupName + ".ReactionEnable";
public const string TagEnable = GroupName + ".TagEnable"; public const string TagEnable = GroupName + ".TagEnable";
public const string MarkedItemEnable = GroupName + ".MarkedItemEnable";
} }

3
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/GlobalCmsKitFeatures.cs

@ -29,6 +29,8 @@ public class GlobalCmsKitFeatures : GlobalModuleFeatures
public BlogPostScrollIndexFeature BlogPostScrollIndex => GetFeature<BlogPostScrollIndexFeature>(); public BlogPostScrollIndexFeature BlogPostScrollIndex => GetFeature<BlogPostScrollIndexFeature>();
public MarkedItemsFeature MarkedItemsFeature => GetFeature<MarkedItemsFeature>();
public GlobalCmsKitFeatures([NotNull] GlobalFeatureManager featureManager) public GlobalCmsKitFeatures([NotNull] GlobalFeatureManager featureManager)
: base(featureManager) : base(featureManager)
{ {
@ -43,5 +45,6 @@ public class GlobalCmsKitFeatures : GlobalModuleFeatures
AddFeature(new MenuFeature(this)); AddFeature(new MenuFeature(this));
AddFeature(new GlobalResourcesFeature(this)); AddFeature(new GlobalResourcesFeature(this));
AddFeature(new BlogPostScrollIndexFeature(this)); AddFeature(new BlogPostScrollIndexFeature(this));
AddFeature(new MarkedItemsFeature(this));
} }
} }

27
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/MarkedItemsFeature.cs

@ -0,0 +1,27 @@
using JetBrains.Annotations;
using Volo.Abp.GlobalFeatures;
namespace Volo.CmsKit.GlobalFeatures;
[GlobalFeatureName(Name)]
public class MarkedItemsFeature : GlobalFeature
{
public const string Name = "CmsKit.MarkedItems";
internal MarkedItemsFeature(
[NotNull] GlobalCmsKitFeatures cmsKit
) : base(cmsKit)
{
}
public override void Enable()
{
var userFeature = FeatureManager.Modules.CmsKit().User;
if (!userFeature.IsEnabled)
{
userFeature.Enable();
}
base.Enable();
}
}

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

@ -25,9 +25,15 @@
"CmsKit:Page:0001": "عنوان url المقدم ({Slug}) موجود بالفعل. يرجى المحاولة مع عنوان url مختلف.", "CmsKit:Page:0001": "عنوان url المقدم ({Slug}) موجود بالفعل. يرجى المحاولة مع عنوان url مختلف.",
"CmsKit:Rating:0001": "لا يمكن تصنيف الكيان {EntityType}.", "CmsKit:Rating:0001": "لا يمكن تصنيف الكيان {EntityType}.",
"CmsKit:Reaction:0001": "لا يمكن أن يحتوي الكيان {EntityType} على ردود أفعال.", "CmsKit:Reaction:0001": "لا يمكن أن يحتوي الكيان {EntityType} على ردود أفعال.",
"CmsKit:MarkedItem:0001": "لا يمكن أن تمييز الكيان {EntityType}.",
"CmsKit:Tag:0002": "الكيان غير قابل للوسم!", "CmsKit:Tag:0002": "الكيان غير قابل للوسم!",
"CommentAuthorizationExceptionMessage": "هذه التعليقات غير مسموح بها للعرض العام.", "CommentAuthorizationExceptionMessage": "هذه التعليقات غير مسموح بها للعرض العام.",
"CommentDeletionConfirmationMessage": "سيتم حذف هذا التعليق وجميع الردود!", "CommentDeletionConfirmationMessage": "سيتم حذف هذا التعليق وجميع الردود!",
"CmsKit:Modals:Login": "تسجيل الدخول",
"CmsKit:Modals:LoginModalDefaultMessage": "سجل الدخول لتتمكن من اجراء هذه العملية",
"CmsKit:Modals:YouAreNotAuthenticated": "انت غير مصرح",
"CmsKit:MarkedItem:LoginMessage": "الرجاء تسجيل الدخول لتحديد هذا العنصر.",
"CmsKit:MarkedItem:ToggleConfirmation": "هل أنت متأكد أنك تريد تغيير حالة العنصر المميز؟",
"Comments": "تعليقات", "Comments": "تعليقات",
"Content": "المحتوى", "Content": "المحتوى",
"ContentDeletionConfirmationMessage": "هل أنت متأكد من حذف هذا المحتوى؟", "ContentDeletionConfirmationMessage": "هل أنت متأكد من حذف هذا المحتوى؟",
@ -212,6 +218,8 @@
"Feature:RatingEnableDescription": "نظام تصنيف CMS Kit الذي يسمح للمستخدمين بتقييم الكيانات مثل BlogPost.", "Feature:RatingEnableDescription": "نظام تصنيف CMS Kit الذي يسمح للمستخدمين بتقييم الكيانات مثل BlogPost.",
"Feature:ReactionEnable": "رد فعل", "Feature:ReactionEnable": "رد فعل",
"Feature:ReactionEnableDescription": "نظام التفاعل الخاص بـ CMS Kit الذي يسمح للمستخدمين بإرسال ردود أفعال إلى كيانات مثل BlogPost، والتعليقات، وما إلى ذلك.", "Feature:ReactionEnableDescription": "نظام التفاعل الخاص بـ CMS Kit الذي يسمح للمستخدمين بإرسال ردود أفعال إلى كيانات مثل BlogPost، والتعليقات، وما إلى ذلك.",
"Feature:MarkedItemEnable": "تمييز العنصر",
"Feature:MarkedItemEnableDescription": "نظام التفاعل الخاص بـ CMS Kit الذي يسمح للمستخدمين بتمييز الكيانات كجعلها مفضلة.",
"Feature:TagEnable": "وضع العلامات", "Feature:TagEnable": "وضع العلامات",
"Feature:TagEnableDescription": "نظام علامات CMS Kit الذي يسمح بوضع علامات على الكيانات مثل BlogPost.", "Feature:TagEnableDescription": "نظام علامات CMS Kit الذي يسمح بوضع علامات على الكيانات مثل BlogPost.",
"DeleteBlogPostMessage": "سيتم حذف المدونة. هل أنت متأكد؟", "DeleteBlogPostMessage": "سيتم حذف المدونة. هل أنت متأكد؟",

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

@ -1,249 +1,257 @@
{ {
"culture": "en", "culture": "en",
"texts": { "texts": {
"AddSubMenuItem": "Add Sub Menu Item", "AddSubMenuItem": "Add Sub Menu Item",
"AreYouSure": "Are You Sure?", "AreYouSure": "Are You Sure?",
"BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?", "BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?",
"BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.", "BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.",
"BlogId": "Blog", "BlogId": "Blog",
"BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?", "BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?",
"BlogPosts": "Blog posts", "BlogPosts": "Blog posts",
"Blogs": "Blogs", "Blogs": "Blogs",
"ChoosePreference": "Choose Preference...", "ChoosePreference": "Choose Preference...",
"Cms": "CMS", "Cms": "CMS",
"CmsKit.Comments": "Comments", "CmsKit.Comments": "Comments",
"CmsKit.Ratings": "Ratings", "CmsKit.Ratings": "Ratings",
"CmsKit.Reactions": "Reactions", "CmsKit.Reactions": "Reactions",
"CmsKit.Tags": "Tags", "CmsKit.Tags": "Tags",
"CmsKit:0002": "Content already exists!", "CmsKit:0002": "Content already exists!",
"CmsKit:0003": "The entity {0} is not taggable.", "CmsKit:0003": "The entity {0} is not taggable.",
"CmsKit:Blog:0001": "The given slug ({Slug}) already exists!", "CmsKit:Blog:0001": "The given slug ({Slug}) already exists!",
"CmsKit:BlogPost:0001": "The given slug already exists!", "CmsKit:BlogPost:0001": "The given slug already exists!",
"CmsKit:Comments:0001": "The entity {EntityType} is not commentable.", "CmsKit:Comments:0001": "The entity {EntityType} is not commentable.",
"CmsKit:Media:0001": "'{Name}' is not a valid media name.", "CmsKit:Media:0001": "'{Name}' is not a valid media name.",
"CmsKit:Media:0002": "The entity can't have media.", "CmsKit:Media:0002": "The entity can't have media.",
"CmsKit:Page:0001": "The given url ({Slug}) already exists. Please try with different url.", "CmsKit:Page:0001": "The given url ({Slug}) already exists. Please try with different url.",
"CmsKit:Rating:0001": "The entity {EntityType} can't be rated.", "CmsKit:Rating:0001": "The entity {EntityType} can't be rated.",
"CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.", "CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.",
"CmsKit:Tag:0002": "The entity is not taggable!", "CmsKit:Tag:0002": "The entity is not taggable!",
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.", "CmsKit:MarkedItem:ToggleConfirmation": "Are you sure you want to toggle the marked item?",
"CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!", "CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
"Comments": "Comments", "CmsKit:Modals:Login": "Login",
"Content": "Content", "CmsKit:Modals:LoginModalDefaultMessage": "Please login to continue!",
"ContentDeletionConfirmationMessage": "Are you sure to delete this content?", "CmsKit:Modals:YouAreNotAuthenticated": "This operation is not authorized for you.",
"Contents": "Contents", "CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!",
"CoverImage": "Cover image", "CmsKit:MarkedItem:0001": "The entity {EntityType} can't be marked.",
"CreateBlogPostPage": "New blog post", "CmsKit:MarkedItem:LoginMessage": "Please login to mark this item.",
"CreationTime": "Creation time", "Comments": "Comments",
"Delete": "Delete", "Content": "Content",
"Detail": "Detail", "ContentDeletionConfirmationMessage": "Are you sure to delete this content?",
"Details": "Details", "Contents": "Contents",
"DisplayName": "Display name", "CoverImage": "Cover image",
"DoYouPreferAdditionalEmails": "Do you prefer additional emails?", "CreateBlogPostPage": "New blog post",
"Edit": "Edit", "CreationTime": "Creation time",
"EndDate": "End date", "Delete": "Delete",
"EntityId": "Entity Id", "Detail": "Detail",
"EntityType": "Entity type", "Details": "Details",
"ExportCSV": "Export CSV", "DisplayName": "Display name",
"Features": "Features", "DoYouPreferAdditionalEmails": "Do you prefer additional emails?",
"GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?", "Edit": "Edit",
"IsActive": "Active", "EndDate": "End date",
"LastModification": "Last Modification", "EntityId": "Entity Id",
"LastModificationTime": "Last Modification Time", "EntityType": "Entity type",
"LoginToAddComment": "Login to add comment", "ExportCSV": "Export CSV",
"LoginToRate": "Login to rate", "Features": "Features",
"LoginToReact": "Login to react", "GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?",
"LoginToReply": "Login to reply", "IsActive": "Active",
"MainMenu": "Main Menu", "LastModification": "Last Modification",
"MakeMainMenu": "Make main menu", "LastModificationTime": "Last Modification Time",
"Menu:CMS": "CMS", "LoginToAddComment": "Login to add comment",
"Menus": "Menus", "LoginToRate": "Login to rate",
"MenuDeletionConfirmationMessage": "The menu '{0}' will be deleted. Are you sure?", "LoginToReact": "Login to react",
"MenuItemDeletionConfirmationMessage": "Are sure to delete this menu item?", "LoginToReply": "Login to reply",
"MenuItemMoveConfirmMessage": "Are you sure you want to move '{0}' under '{1}'?", "MainMenu": "Main Menu",
"MenuItems": "Menu items", "MakeMainMenu": "Make main menu",
"Message": "Message", "Menu:CMS": "CMS",
"MessageDeletionConfirmationMessage": "This comment will be deleted completely.", "Menus": "Menus",
"NewBlog": "New blog", "MenuDeletionConfirmationMessage": "The menu '{0}' will be deleted. Are you sure?",
"NewBlogPost": "New blog post", "MenuItemDeletionConfirmationMessage": "Are sure to delete this menu item?",
"NewMenu": "New menu", "MenuItemMoveConfirmMessage": "Are you sure you want to move '{0}' under '{1}'?",
"NewMenuItem": "New root menu item", "MenuItems": "Menu items",
"NewPage": "New page", "Message": "Message",
"NewTag": "New tag", "MessageDeletionConfirmationMessage": "This comment will be deleted completely.",
"NoMenuItems": "There is no menu item yet!", "NewBlog": "New blog",
"OK": "OK", "NewBlogPost": "New blog post",
"PageDeletionConfirmationMessage": "Are you sure to delete this page?", "NewMenu": "New menu",
"PageId": "Page", "NewMenuItem": "New root menu item",
"Pages": "Pages", "NewPage": "New page",
"PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.", "NewTag": "New tag",
"BlogSlugInformation": "Slug is used on url. Your url will be '/{0}/{{slug}}'.", "NoMenuItems": "There is no menu item yet!",
"Permission:BlogManagement": "Blog management", "OK": "OK",
"Permission:BlogManagement.Create": "Create", "PageDeletionConfirmationMessage": "Are you sure to delete this page?",
"Permission:BlogManagement.Delete": "Delete", "PageId": "Page",
"Permission:BlogManagement.Features": "Features", "Pages": "Pages",
"Permission:BlogManagement.Update": "Update", "PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.",
"Permission:BlogPostManagement": "Blog post management", "BlogSlugInformation": "Slug is used on url. Your url will be '/{0}/{{slug}}'.",
"Permission:BlogPostManagement.Create": "Create", "Permission:BlogManagement": "Blog management",
"Permission:BlogPostManagement.Delete": "Delete", "Permission:BlogManagement.Create": "Create",
"Permission:BlogPostManagement.Update": "Update", "Permission:BlogManagement.Delete": "Delete",
"Permission:BlogPostManagement.Publish": "Publish", "Permission:BlogManagement.Features": "Features",
"Permission:CmsKit": "CmsKit admin", "Permission:BlogManagement.Update": "Update",
"Permission:Comments": "Comment management", "Permission:BlogPostManagement": "Blog post management",
"Permission:Comments.Delete": "Delete", "Permission:BlogPostManagement.Create": "Create",
"Permission:Contents": "Content management", "Permission:BlogPostManagement.Delete": "Delete",
"Permission:Contents.Create": "Create content", "Permission:BlogPostManagement.Update": "Update",
"Permission:Contents.Delete": "Delete content", "Permission:BlogPostManagement.Publish": "Publish",
"Permission:Contents.Update": "Update content", "Permission:CmsKit": "CmsKit admin",
"Permission:MediaDescriptorManagement": "Media management", "Permission:Comments": "Comment management",
"Permission:MediaDescriptorManagement:Create": "Create", "Permission:Comments.Delete": "Delete",
"Permission:MediaDescriptorManagement:Delete": "Delete", "Permission:Contents": "Content management",
"Permission:MenuItemManagement": "Menu item management", "Permission:Contents.Create": "Create content",
"Permission:MenuItemManagement.Create": "Create", "Permission:Contents.Delete": "Delete content",
"Permission:MenuItemManagement.Delete": "Delete", "Permission:Contents.Update": "Update content",
"Permission:MenuItemManagement.Update": "Update", "Permission:MediaDescriptorManagement": "Media management",
"Permission:MenuManagement": "Menu management", "Permission:MediaDescriptorManagement:Create": "Create",
"Permission:MenuManagement.Create": "Create", "Permission:MediaDescriptorManagement:Delete": "Delete",
"Permission:MenuManagement.Delete": "Delete", "Permission:MenuItemManagement": "Menu item management",
"Permission:MenuManagement.Update": "Update", "Permission:MenuItemManagement.Create": "Create",
"Permission:Menus": "Menu management", "Permission:MenuItemManagement.Delete": "Delete",
"Permission:Menus.Create": "Create", "Permission:MenuItemManagement.Update": "Update",
"Permission:Menus.Delete": "Delete", "Permission:MenuManagement": "Menu management",
"Permission:Menus.Update": "Update", "Permission:MenuManagement.Create": "Create",
"Permission:PageManagement": "Page management", "Permission:MenuManagement.Delete": "Delete",
"Permission:PageManagement:Create": "Create", "Permission:MenuManagement.Update": "Update",
"Permission:PageManagement:Delete": "Delete", "Permission:Menus": "Menu management",
"Permission:PageManagement:Update": "Update", "Permission:Menus.Create": "Create",
"Permission:PageManagement:SetAsHomePage": "Set as home page", "Permission:Menus.Delete": "Delete",
"Permission:TagManagement": "Tag management", "Permission:Menus.Update": "Update",
"Permission:TagManagement.Create": "Create", "Permission:PageManagement": "Page management",
"Permission:TagManagement.Delete": "Delete", "Permission:PageManagement:Create": "Create",
"Permission:TagManagement.Update": "Update", "Permission:PageManagement:Delete": "Delete",
"Permission:GlobalResources": "Global resources", "Permission:PageManagement:Update": "Update",
"Permission:CmsKitPublic": "CmsKit public", "Permission:PageManagement:SetAsHomePage": "Set as home page",
"Permission:Comments.DeleteAll": "Delete all", "Permission:TagManagement": "Tag management",
"PickYourReaction": "Pick your reaction", "Permission:TagManagement.Create": "Create",
"Rating": "Rating", "Permission:TagManagement.Delete": "Delete",
"RatingUndoMessage": "Your rating will be undo.", "Permission:TagManagement.Update": "Update",
"Reactions": "Reactions", "Permission:GlobalResources": "Global resources",
"Read": "Read", "Permission:CmsKitPublic": "CmsKit public",
"RepliesToThisComment": "Replies to this comment", "Permission:Comments.DeleteAll": "Delete all",
"Reply": "Reply", "PickYourReaction": "Pick your reaction",
"ReplyTo": "Reply to", "Rating": "Rating",
"SamplePageMessage": "A sample page for the Pro module", "RatingUndoMessage": "Your rating will be undo.",
"SaveChanges": "Save changes", "Reactions": "Reactions",
"Script": "Script", "Read": "Read",
"SelectAll": "Select all", "RepliesToThisComment": "Replies to this comment",
"Send": "Send", "Reply": "Reply",
"SendMessage": "Send Message", "ReplyTo": "Reply to",
"SelectedAuthor": "Author", "SamplePageMessage": "A sample page for the Pro module",
"ShortDescription": "Short description", "SaveChanges": "Save changes",
"Slug": "Slug", "Script": "Script",
"Source": "Source", "SelectAll": "Select all",
"SourceUrl": "Source Url", "Send": "Send",
"Star": "Star", "SendMessage": "Send Message",
"StartDate": "Start Date", "SelectedAuthor": "Author",
"Style": "Style", "ShortDescription": "Short description",
"Subject": "Subject", "Slug": "Slug",
"SubjectPlaceholder": "Please type a subject", "Source": "Source",
"Submit": "Submit", "SourceUrl": "Source Url",
"Subscribe": "Subscribe", "Star": "Star",
"SavedSuccessfully": "Saved successfully!", "StartDate": "Start Date",
"TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?", "Style": "Style",
"Tags": "Tags", "Subject": "Subject",
"Text": "Text", "SubjectPlaceholder": "Please type a subject",
"ThankYou": "Thank you", "Submit": "Submit",
"Title": "Title", "Subscribe": "Subscribe",
"Undo": "Undo", "SavedSuccessfully": "Saved successfully!",
"Update": "Update", "TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?",
"UpdatePreferenceSuccessMessage": "Your preferences have been saved.", "Tags": "Tags",
"UpdateYourEmailPreferences": "Update your email preferences", "Text": "Text",
"UnMakeMainMenu": "Unmake Main Menu", "ThankYou": "Thank you",
"UploadFailedMessage": "Upload failed.", "Title": "Title",
"UserId": "User Id", "Undo": "Undo",
"Username": "Username", "Update": "Update",
"YourComment": "Your comment", "UpdatePreferenceSuccessMessage": "Your preferences have been saved.",
"YourEmailAddress": "Your e-mail address", "UpdateYourEmailPreferences": "Update your email preferences",
"YourFullName": "Your full name", "UnMakeMainMenu": "Unmake Main Menu",
"YourMessage": "Your Message", "UploadFailedMessage": "Upload failed.",
"YourReply": "Your reply", "UserId": "User Id",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.", "Username": "Username",
"GlobalResources": "Global resources", "YourComment": "Your comment",
"CmsKit.BlogPost.Status.0": "Draft", "YourEmailAddress": "Your e-mail address",
"CmsKit.BlogPost.Status.1": "Published", "YourFullName": "Your full name",
"CmsKit.BlogPost.Status.2": "Waiting for review", "YourMessage": "Your Message",
"BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?", "YourReply": "Your reply",
"SuccessfullyPublished": "Successfully published!", "MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
"Draft": "Draft", "GlobalResources": "Global resources",
"Publish": "Publish", "CmsKit.BlogPost.Status.0": "Draft",
"BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?", "CmsKit.BlogPost.Status.1": "Published",
"BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?", "CmsKit.BlogPost.Status.2": "Waiting for review",
"SaveAsDraft": "Save as draft", "BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?",
"SendToReview": "Send to review", "SuccessfullyPublished": "Successfully published!",
"SendToReviewToPublish": "Send to review to publish", "Draft": "Draft",
"BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.", "Publish": "Publish",
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.", "BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?",
"SelectAStatus": "Select a status", "BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?",
"Status": "Status", "SaveAsDraft": "Save as draft",
"CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts", "SendToReview": "Send to review",
"CmsKit.BlogPost.PreventXssFeature": "Prevent XSS", "SendToReviewToPublish": "Send to review to publish",
"Add": "Add", "BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.",
"AddWidget": "Add Widget", "HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
"PleaseConfigureWidgets": "Please configure widgets", "SelectAStatus": "Select a status",
"SelectAnAuthor": "Select an Author", "Status": "Status",
"InThisDocument": "In This Document", "CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts",
"GoToTop": "Go To Top", "CmsKit.BlogPost.PreventXssFeature": "Prevent XSS",
"SetAsHomePage": "Change Home Page Status", "Add": "Add",
"CompletedSettingAsHomePage": "Set as home page", "AddWidget": "Add Widget",
"IsHomePage": "Is Home Page", "PleaseConfigureWidgets": "Please configure widgets",
"RemovedSettingAsHomePage": "Removed setting the home page", "SelectAnAuthor": "Select an Author",
"Feature:CmsKitGroup": "Cms kit", "InThisDocument": "In This Document",
"Feature:BlogEnable": "Blogpost", "GoToTop": "Go To Top",
"Feature:BlogEnableDescription": "CMS Kit's blogpost system that allows create blogs and posts dynamically in the application.", "SetAsHomePage": "Change Home Page Status",
"Feature:CommentEnable": "Commenting", "CompletedSettingAsHomePage": "Set as home page",
"Feature:CommentEnableDescription": "CMS Kit's comment system allows commenting on entities such as BlogPost.", "IsHomePage": "Is Home Page",
"Feature:GlobalResourceEnable": "Global resourcing", "RemovedSettingAsHomePage": "Removed setting the home page",
"Feature:GlobalResourceEnableDescription": "CMS Kit's global resoruces feature that allows managing global styles & scripts.", "Feature:CmsKitGroup": "Cms kit",
"Feature:MenuEnable": "Menu", "Feature:BlogEnable": "Blogpost",
"Feature:MenuEnableDescription": "CMS Kit's dynamic menu system that allows adding/removing application menus dynamically.", "Feature:BlogEnableDescription": "CMS Kit's blogpost system that allows create blogs and posts dynamically in the application.",
"Feature:PageEnable": "Paging", "Feature:CommentEnable": "Commenting",
"Feature:PageEnableDescription": "CMS Kit's page system that allows creating static pages with specific URL.", "Feature:CommentEnableDescription": "CMS Kit's comment system allows commenting on entities such as BlogPost.",
"Feature:RatingEnable": "Rating", "Feature:GlobalResourceEnable": "Global resourcing",
"Feature:RatingEnableDescription": "CMS Kit's rating system that allows users to rate entities such as BlogPost.", "Feature:GlobalResourceEnableDescription": "CMS Kit's global resoruces feature that allows managing global styles & scripts.",
"Feature:ReactionEnable": "Reaction", "Feature:MenuEnable": "Menu",
"Feature:ReactionEnableDescription": "CMS Kit's reaction system that allows users to send reactions to entities such as BlogPost, Comments, etc.", "Feature:MenuEnableDescription": "CMS Kit's dynamic menu system that allows adding/removing application menus dynamically.",
"Feature:TagEnable": "Taging", "Feature:PageEnable": "Paging",
"Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.", "Feature:PageEnableDescription": "CMS Kit's page system that allows creating static pages with specific URL.",
"DeleteBlogPostMessage": "The blog will be deleted. Are you sure?", "Feature:RatingEnable": "Rating",
"CaptchaCode": "Captcha code", "Feature:RatingEnableDescription": "CMS Kit's rating system that allows users to rate entities such as BlogPost.",
"CommentTextRequired": "Comment is required", "Feature:ReactionEnable": "Reaction",
"CaptchaCodeErrorMessage": "The answer you entered for the CAPTCHA was not correct. Please try again", "Feature:ReactionEnableDescription": "CMS Kit's reaction system that allows users to send reactions to entities such as BlogPost, Comments, etc.",
"CaptchaCodeMissingMessage": "The captcha code is missing!", "Feature:TagEnable": "Taging",
"UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL.", "Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.",
"URL": "URL", "Feature:MarkedItemEnable": "Marked Item",
"PopularTags": "Popular Tags", "Feature:MarkedItemEnableDescription": "The CMS Kit's marking system that allows users to mark entities as favorites.",
"RemoveCoverImageConfirmationMessage": "Are you sure you want to remove the cover image?", "DeleteBlogPostMessage": "The blog will be deleted. Are you sure?",
"RemoveCoverImage": "Remove cover image", "CaptchaCode": "Captcha code",
"CssClass": "CSS Class", "CommentTextRequired": "Comment is required",
"TagsHelpText": "Tags should be comma-separated (e.g.: tag1, tag2, tag3)", "CaptchaCodeErrorMessage": "The answer you entered for the CAPTCHA was not correct. Please try again",
"ThisPartOfContentCouldntBeLoaded": "This part of content couldn't be loaded.", "CaptchaCodeMissingMessage": "The captcha code is missing!",
"DuplicateCommentAttemptMessage": "Duplicate comment post attempt detected. Your comment has already been submitted.", "UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL.",
"NoBlogPostYet": "No blog post yet!", "URL": "URL",
"CmsKit:Comment": "Comment", "PopularTags": "Popular Tags",
"CmsKitCommentOptions:RequireApprovement": "Require approval for comments", "RemoveCoverImageConfirmationMessage": "Are you sure you want to remove the cover image?",
"CmsKitCommentOptions:RequireApprovementDescription": "When enabled, comments will require approval before being published.", "RemoveCoverImage": "Remove cover image",
"CommentFilter:ApproveState":"Approve State", "CssClass": "CSS Class",
"ApproveState": "Approve State", "TagsHelpText": "Tags should be comma-separated (e.g.: tag1, tag2, tag3)",
"CommentFilter:0":"All", "ThisPartOfContentCouldntBeLoaded": "This part of content couldn't be loaded.",
"CommentFilter:1":"Approved", "DuplicateCommentAttemptMessage": "Duplicate comment post attempt detected. Your comment has already been submitted.",
"CommentFilter:2":"Disapproved", "NoBlogPostYet": "No blog post yet!",
"CommentFilter:4":"Waiting", "CmsKit:Comment": "Comment",
"ApprovedSuccessfully":"Approved Successfully", "CmsKitCommentOptions:RequireApprovement": "Require approval for comments",
"ApprovalRevokedSuccessfully":"Approval Revoked Successfully", "CmsKitCommentOptions:RequireApprovementDescription": "When enabled, comments will require approval before being published.",
"Approve":"Approve", "CommentFilter:ApproveState": "Approve State",
"Disapproved":"Disapproved", "ApproveState": "Approve State",
"CommentAlertMessage":"There are {0} comments waiting for approval", "CommentFilter:0": "All",
"Settings:Menu:CmsKit":"CMS", "CommentFilter:1": "Approved",
"CommentsAwaitingApproval":"Comments Awaiting Approval", "CommentFilter:2": "Disapproved",
"CommentSubmittedForApproval": "Your comment has been submitted for approval.", "CommentFilter:4": "Waiting",
} "ApprovedSuccessfully": "Approved Successfully",
"ApprovalRevokedSuccessfully": "Approval Revoked Successfully",
"Approve": "Approve",
"Disapproved": "Disapproved",
"CommentAlertMessage": "There are {0} comments waiting for approval",
"Settings:Menu:CmsKit": "CMS",
"CommentsAwaitingApproval": "Comments Awaiting Approval",
"CommentSubmittedForApproval": "Your comment has been submitted for approval."
}
} }

9
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MarkedItems/StandardMarkedItems.cs

@ -0,0 +1,9 @@
namespace Volo.CmsKit.MarkedItems;
public static class StandardMarkedItems
{
public const string Favorite = "_FA";
public const string Flagged = "_FL";
public const string Bookmark = "_BO";
public const string Starred = "_ST";
}

9
modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MarkedItems/UserMarkedItemConsts.cs

@ -0,0 +1,9 @@
using Volo.CmsKit.Entities;
namespace Volo.CmsKit.MarkedItems;
public static class UserMarkedItemConsts
{
public static int MaxEntityTypeLength { get; set; } = CmsEntityConsts.MaxEntityTypeLength;
public static int MaxEntityIdLength { get; set; } = CmsEntityConsts.MaxEntityIdLength;
}

10
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/CmsKitMarkedItemOptions.cs

@ -0,0 +1,10 @@
using JetBrains.Annotations;
using System.Collections.Generic;
namespace Volo.CmsKit.MarkedItems;
public class CmsKitMarkedItemOptions
{
[NotNull]
public List<MarkedItemEntityTypeDefinition> EntityTypes { get; } = new();
}

36
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/DefaultMarkedItemDefinitionStore.cs

@ -0,0 +1,36 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using Volo.Abp;
namespace Volo.CmsKit.MarkedItems;
public class DefaultMarkedItemDefinitionStore : IMarkedItemDefinitionStore
{
protected CmsKitMarkedItemOptions Options { get; }
public DefaultMarkedItemDefinitionStore(IOptions<CmsKitMarkedItemOptions> options)
{
Options = options.Value;
}
public virtual Task<bool> IsDefinedAsync([NotNull] string entityType)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
var isDefined = Options.EntityTypes.Any(x => x.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase));
return Task.FromResult(isDefined);
}
public virtual Task<MarkedItemEntityTypeDefinition> GetAsync([NotNull] string entityType)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
var definition = Options.EntityTypes.SingleOrDefault(x => x.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase));
return Task.FromResult(definition);
}
}

16
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/EntityCannotBeMarkedException.cs

@ -0,0 +1,16 @@
using JetBrains.Annotations;
using Volo.Abp;
namespace Volo.CmsKit.MarkedItems;
public class EntityCannotBeMarkedException : BusinessException
{
public EntityCannotBeMarkedException([NotNull] string entityType)
{
EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType));
Code = CmsKitErrorCodes.MarkedItems.EntityCannotBeMarked;
WithData(nameof(EntityType), EntityType);
}
public string EntityType { get; }
}

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

@ -0,0 +1,8 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.CmsKit.MarkedItems;
public interface IMarkedItemDefinitionStore : IEntityTypeDefinitionStore<MarkedItemEntityTypeDefinition>
{
}

31
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/IUserMarkedItemRepository.cs

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Domain.Repositories;
namespace Volo.CmsKit.MarkedItems;
public interface IUserMarkedItemRepository : IBasicRepository<UserMarkedItem, Guid>
{
Task<UserMarkedItem> FindAsync(
Guid userId,
[NotNull] string entityType,
[NotNull] string entityId,
CancellationToken cancellationToken = default
);
Task<List<UserMarkedItem>> GetListForUserAsync(
Guid userId,
[NotNull] string entityType,
CancellationToken cancellationToken = default
);
Task<IQueryable<UserMarkedItem>> GetQueryForUserAsync(
[NotNull] string entityType,
[NotNull] Guid userId,
CancellationToken cancellationToken = default
);
}

16
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/MarkedItemEntityTypeDefinition.cs

@ -0,0 +1,16 @@
using JetBrains.Annotations;
using Volo.Abp;
namespace Volo.CmsKit.MarkedItems;
public class MarkedItemEntityTypeDefinition : EntityTypeDefinition
{
public string IconName { get; set; }
public MarkedItemEntityTypeDefinition(
[NotNull] string entityType,
[NotNull] string iconName) : base(entityType)
{
Check.NotNull(iconName, nameof(iconName));
IconName = iconName;
}
}

58
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/MarkedItemManager.cs

@ -0,0 +1,58 @@
using System;
using JetBrains.Annotations;
using System.Threading.Tasks;
using Volo.Abp;
namespace Volo.CmsKit.MarkedItems;
public class MarkedItemManager : CmsKitDomainServiceBase
{
IMarkedItemDefinitionStore MarkedItemDefinitionStore { get; set; }
IUserMarkedItemRepository UserMarkedItemRepository { get; set; }
public MarkedItemManager(
IUserMarkedItemRepository userMarkedItemRepository,
IMarkedItemDefinitionStore markedItemDefinitionStore)
{
UserMarkedItemRepository = userMarkedItemRepository;
MarkedItemDefinitionStore = markedItemDefinitionStore;
}
public virtual async Task<bool> ToggleAsync(
Guid creatorId,
[NotNull] string entityType,
[NotNull] string entityId)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
var markedItem = await UserMarkedItemRepository.FindAsync(creatorId, entityType, entityId);
if (markedItem != null)
{
await UserMarkedItemRepository.DeleteAsync(markedItem);
return false;
}
if (!await MarkedItemDefinitionStore.IsDefinedAsync(entityType))
{
throw new EntityCannotBeMarkedException(entityType);
}
await UserMarkedItemRepository.InsertAsync(
new UserMarkedItem(
GuidGenerator.Create(),
entityType,
entityId,
creatorId,
CurrentTenant.Id
)
);
return true;
}
public virtual async Task<MarkedItemEntityTypeDefinition> GetAsync(
[NotNull] string entityType)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
return await MarkedItemDefinitionStore.GetAsync(entityType);
}
}

36
modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MarkedItems/UserMarkedItem.cs

@ -0,0 +1,36 @@
using System;
using Volo.Abp;
using Volo.Abp.Auditing;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace Volo.CmsKit.MarkedItems;
public class UserMarkedItem : BasicAggregateRoot<Guid>, IHasCreationTime, IMustHaveCreator, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual Guid CreatorId { get; set; }
public virtual DateTime CreationTime { get; set; }
public string EntityId { get; protected set; }
public string EntityType { get; protected set; }
protected UserMarkedItem() { }
internal UserMarkedItem(
Guid id,
[NotNull] string entityType,
[NotNull] string entityId,
Guid creatorId,
Guid? tenantId = null)
: base(id)
{
EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
EntityId = Check.NotNullOrWhiteSpace(entityId, nameof(entityId));
CreatorId = creatorId;
TenantId = tenantId;
}
}

2
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs

@ -4,6 +4,7 @@ using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -30,6 +31,7 @@ public class CmsKitDbContext : AbpDbContext<CmsKitDbContext>, ICmsKitDbContext
public DbSet<MediaDescriptor> MediaDescriptors { get; set; } public DbSet<MediaDescriptor> MediaDescriptors { get; set; }
public DbSet<MenuItem> MenuItems { get; set; } public DbSet<MenuItem> MenuItems { get; set; }
public DbSet<GlobalResource> GlobalResources { get; set; } public DbSet<GlobalResource> GlobalResources { get; set; }
public DbSet<UserMarkedItem> UserMarkedItems { get; set; }
public CmsKitDbContext(DbContextOptions<CmsKitDbContext> options) public CmsKitDbContext(DbContextOptions<CmsKitDbContext> options)
: base(options) : base(options)

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

@ -7,6 +7,7 @@ using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -285,6 +286,28 @@ public static class CmsKitDbContextModelCreatingExtensions
builder.Ignore<GlobalResource>(); builder.Ignore<GlobalResource>();
} }
if (GlobalFeatureManager.Instance.IsEnabled<MarkedItemsFeature>())
{
builder.Entity<UserMarkedItem>(b =>
{
b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "UserMarkedItems", AbpCmsKitDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.EntityType).IsRequired();
b.Property(x => x.EntityId).IsRequired();
b.HasIndex(x => new { x.TenantId, x.EntityType, x.EntityId });
b.HasIndex(x => new { x.TenantId, x.CreatorId, x.EntityType, x.EntityId });
b.ApplyObjectExtensionMappings();
});
}
else
{
builder.Ignore<UserMarkedItem>();
}
builder.TryConfigureObjectExtensions<CmsKitDbContext>(); builder.TryConfigureObjectExtensions<CmsKitDbContext>();
} }
} }

2
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs

@ -11,6 +11,7 @@ using Volo.CmsKit.Ratings;
using Volo.CmsKit.Reactions; using Volo.CmsKit.Reactions;
using Volo.CmsKit.Tags; using Volo.CmsKit.Tags;
using Volo.CmsKit.Users; using Volo.CmsKit.Users;
using Volo.CmsKit.MarkedItems;
namespace Volo.CmsKit.EntityFrameworkCore; namespace Volo.CmsKit.EntityFrameworkCore;
@ -37,6 +38,7 @@ public class CmsKitEntityFrameworkCoreModule : AbpModule
options.AddRepository<BlogFeature, EfCoreBlogFeatureRepository>(); options.AddRepository<BlogFeature, EfCoreBlogFeatureRepository>();
options.AddRepository<MediaDescriptor, EfCoreMediaDescriptorRepository>(); options.AddRepository<MediaDescriptor, EfCoreMediaDescriptorRepository>();
options.AddRepository<GlobalResource, EfCoreGlobalResourceRepository>(); options.AddRepository<GlobalResource, EfCoreGlobalResourceRepository>();
options.AddRepository<UserMarkedItem, EfCoreUserMarkedItemRepository>();
}); });
} }
} }

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

@ -4,6 +4,7 @@ using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -30,4 +31,5 @@ public interface ICmsKitDbContext : IEfCoreDbContext
DbSet<MediaDescriptor> MediaDescriptors { get; } DbSet<MediaDescriptor> MediaDescriptors { get; }
DbSet<MenuItem> MenuItems { get; } DbSet<MenuItem> MenuItems { get; }
DbSet<GlobalResource> GlobalResources { get; } DbSet<GlobalResource> GlobalResources { get; }
DbSet<UserMarkedItem> UserMarkedItems { get; }
} }

67
modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/MarkedItems/EfCoreUserMarkedItemRepository.cs

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.CmsKit.EntityFrameworkCore;
namespace Volo.CmsKit.MarkedItems;
public class EfCoreUserMarkedItemRepository : EfCoreRepository<ICmsKitDbContext, UserMarkedItem, Guid>, IUserMarkedItemRepository
{
public EfCoreUserMarkedItemRepository(IDbContextProvider<ICmsKitDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public async Task<UserMarkedItem> FindAsync(Guid userId, [NotNull] string entityType, [NotNull] string entityId, CancellationToken cancellationToken = default)
{
Check.NotNull(userId, nameof(userId));
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNull(entityId, nameof(entityId));
var entity = await(await GetDbSetAsync())
.Where(x =>
x.CreatorId == userId &&
x.EntityType == entityType &&
x.EntityId == entityId)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
return entity;
}
public async Task<List<UserMarkedItem>> GetListForUserAsync(Guid userId, [NotNull] string entityType, CancellationToken cancellationToken = default)
{
Check.NotNull(userId, nameof(userId));
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
return await(await GetDbSetAsync())
.Where(x =>
x.CreatorId == userId &&
x.EntityType == entityType)
.ToListAsync(GetCancellationToken(cancellationToken));
}
/// <summary>
/// Retrieves an IQueryable representing the user's marked items based on the specified entity type and user ID.
/// </summary>
/// <param name="entityType">The type of entity to filter by.</param>
/// <param name="userId">The ID of the user whose marked items are being retrieved.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>An IQueryable representing the user's marked items filtered by the specified entity type and user ID.</returns>
public async Task<IQueryable<UserMarkedItem>> GetQueryForUserAsync([NotNull] string entityType, [NotNull] Guid userId, CancellationToken cancellationToken = default)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNull(userId, nameof(userId));
var dbSet = await GetDbSetAsync();
var query = dbSet
.Where(x => x.EntityType == entityType && x.CreatorId == userId);
return query;
}
}

3
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs

@ -4,6 +4,7 @@ using Volo.Abp.MongoDB;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -44,6 +45,8 @@ public class CmsKitMongoDbContext : AbpMongoDbContext, ICmsKitMongoDbContext
public IMongoCollection<GlobalResource> GlobalResources => Collection<GlobalResource>(); public IMongoCollection<GlobalResource> GlobalResources => Collection<GlobalResource>();
public IMongoCollection<UserMarkedItem> UserMarkedItems => Collection<UserMarkedItem>();
protected override void CreateModel(IMongoModelBuilder modelBuilder) protected override void CreateModel(IMongoModelBuilder modelBuilder)
{ {
base.CreateModel(modelBuilder); base.CreateModel(modelBuilder);

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

@ -3,6 +3,7 @@ using Volo.Abp.MongoDB;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -84,5 +85,10 @@ public static class CmsKitMongoDbContextExtensions
{ {
x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "GlobalResources"; x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "GlobalResources";
}); });
builder.Entity<UserMarkedItem>(x =>
{
x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "UserMarkedItems";
});
} }
} }

3
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs

@ -5,11 +5,13 @@ using Volo.Abp.Users.MongoDB;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.MongoDB.Blogs; using Volo.CmsKit.MongoDB.Blogs;
using Volo.CmsKit.MongoDB.Comments; using Volo.CmsKit.MongoDB.Comments;
using Volo.CmsKit.MongoDB.GlobalResources; using Volo.CmsKit.MongoDB.GlobalResources;
using Volo.CmsKit.MongoDB.MarkedItems;
using Volo.CmsKit.MongoDB.MediaDescriptors; using Volo.CmsKit.MongoDB.MediaDescriptors;
using Volo.CmsKit.MongoDB.Menus; using Volo.CmsKit.MongoDB.Menus;
using Volo.CmsKit.MongoDB.Pages; using Volo.CmsKit.MongoDB.Pages;
@ -48,6 +50,7 @@ public class CmsKitMongoDbModule : AbpModule
options.AddRepository<MediaDescriptor, MongoMediaDescriptorRepository>(); options.AddRepository<MediaDescriptor, MongoMediaDescriptorRepository>();
options.AddRepository<MenuItem, MongoMenuItemRepository>(); options.AddRepository<MenuItem, MongoMenuItemRepository>();
options.AddRepository<GlobalResource, MongoGlobalResourceRepository>(); options.AddRepository<GlobalResource, MongoGlobalResourceRepository>();
options.AddRepository<UserMarkedItem, MongoUserMarkedItemRepository>();
}); });
} }
} }

3
modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs

@ -4,6 +4,7 @@ using Volo.Abp.MongoDB;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.GlobalResources; using Volo.CmsKit.GlobalResources;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -43,4 +44,6 @@ public interface ICmsKitMongoDbContext : IAbpMongoDbContext
IMongoCollection<MenuItem> MenuItems { get; } IMongoCollection<MenuItem> MenuItems { get; }
IMongoCollection<GlobalResource> GlobalResources { get; } IMongoCollection<GlobalResource> GlobalResources { get; }
IMongoCollection<UserMarkedItem> UserMarkedItems { get; }
} }

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

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using JetBrains.Annotations;
using Volo.Abp;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
using Volo.CmsKit.MarkedItems;
namespace Volo.CmsKit.MongoDB.MarkedItems;
public class MongoUserMarkedItemRepository : MongoDbRepository<ICmsKitMongoDbContext, UserMarkedItem, Guid>, IUserMarkedItemRepository
{
public MongoUserMarkedItemRepository(IMongoDbContextProvider<ICmsKitMongoDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public virtual async Task<UserMarkedItem> FindAsync(Guid userId, [NotNull] string entityType, [NotNull] string entityId, CancellationToken cancellationToken = default)
{
Check.NotNull(userId, nameof(userId));
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNull(entityId, nameof(entityId));
var entity = await (await GetMongoQueryableAsync(cancellationToken))
.Where(x =>
x.CreatorId == userId &&
x.EntityType == entityType &&
x.EntityId == entityId)
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
return entity;
}
public virtual async Task<List<UserMarkedItem>> GetListForUserAsync(Guid userId, [NotNull] string entityType, CancellationToken cancellationToken = default)
{
Check.NotNull(userId, nameof(userId));
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
return await(await GetMongoQueryableAsync(cancellationToken))
.Where(x =>
x.CreatorId == userId &&
x.EntityType == entityType)
.ToListAsync(GetCancellationToken(cancellationToken));
}
/// <summary>
/// Retrieves an IQueryable representing the user's marked items based on the specified entity type and user ID.
/// </summary>
/// <param name="entityType">The type of entity to filter by.</param>
/// <param name="userId">The ID of the user whose marked items are being retrieved.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>An IQueryable representing the user's marked items filtered by the specified entity type and user ID.</returns>
public virtual async Task<IQueryable<UserMarkedItem>> GetQueryForUserAsync([NotNull] string entityType, [NotNull] Guid userId, CancellationToken cancellationToken = default)
{
Check.NotNullOrWhiteSpace(entityType, nameof(entityType));
Check.NotNull(userId, nameof(userId));
var queryable = await GetMongoQueryableAsync(cancellationToken);
var query = queryable
.Where(x => x.EntityType == entityType && x.CreatorId == userId);
return query;
}
}

10
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/MarkedItems/IMarkedItemPublicAppService.cs

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Volo.CmsKit.Public.MarkedItems;
public interface IMarkedItemPublicAppService : IApplicationService
{
Task<MarkedItemWithToggleDto> GetForToggleAsync(string entityType, string entityId);
Task<bool> ToggleAsync(string entityType, string entityId);
}

11
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/MarkedItems/MarkedItemDto.cs

@ -0,0 +1,11 @@
using System;
using JetBrains.Annotations;
namespace Volo.CmsKit.Public.MarkedItems;
[Serializable]
public class MarkedItemDto
{
[NotNull]
public string IconName { get; set; }
}

11
modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/MarkedItems/MarkedItemWithToggleDto.cs

@ -0,0 +1,11 @@
using System;
namespace Volo.CmsKit.Public.MarkedItems;
[Serializable]
public class MarkedItemWithToggleDto
{
public MarkedItemDto MarkedItem { get; set; }
public bool IsMarkedByCurrentUser { get; set; }
}

69
modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicAppService.cs

@ -0,0 +1,69 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Users;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.MarkedItems;
namespace Volo.CmsKit.Public.MarkedItems;
[RequiresGlobalFeature(typeof(MarkedItemsFeature))]
public class MarkedItemPublicAppService : CmsKitPublicAppServiceBase, IMarkedItemPublicAppService
{
public IMarkedItemDefinitionStore MarkedItemDefinitionStore { get; }
public IUserMarkedItemRepository UserMarkedItemRepository { get; }
public MarkedItemManager MarkedItemManager { get; }
public MarkedItemPublicAppService(
IMarkedItemDefinitionStore markedItemDefinitionStore,
IUserMarkedItemRepository userMarkedItemRepository,
MarkedItemManager markedItemManager)
{
MarkedItemDefinitionStore = markedItemDefinitionStore;
UserMarkedItemRepository = userMarkedItemRepository;
MarkedItemManager = markedItemManager;
}
[AllowAnonymous]
public virtual async Task<MarkedItemWithToggleDto> GetForToggleAsync(string entityType, string entityId)
{
var markedItem = await MarkedItemManager.GetAsync(entityType);
var userMarkedItem = CurrentUser.IsAuthenticated
? (await UserMarkedItemRepository
.FindAsync(
CurrentUser.GetId(),
entityType,
entityId
))
: null;
return new MarkedItemWithToggleDto
{
MarkedItem = ConvertToMarkedItemDto(markedItem),
IsMarkedByCurrentUser = userMarkedItem != null
};
}
[Authorize]
public virtual async Task<bool> ToggleAsync(string entityType, string entityId)
{
return await MarkedItemManager.ToggleAsync(
CurrentUser.GetId(),
entityType,
entityId
);
}
private MarkedItemDto ConvertToMarkedItemDto(MarkedItemEntityTypeDefinition markedItemEntityTypeDefinition)
{
return new MarkedItemDto
{
IconName = markedItemEntityTypeDefinition.IconName
};
}
}

15
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Blogs/BlogPostFilteredPagedAndSortedResultRequestDto.cs

@ -0,0 +1,15 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Blogs;
public class BlogPostFilteredPagedAndSortedResultRequestDto : PagedAndSortedResultRequestDto
{
public string Filter { get; set; }
}

17
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Blogs/BlogPostGetListInput.cs

@ -0,0 +1,17 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Blogs;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Blogs;
public class BlogPostGetListInput : PagedAndSortedResultRequestDto
{
public Guid? AuthorId { get; set; }
public Guid? TagId { get; set; }
}

28
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs

@ -0,0 +1,28 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Public.Blogs;
using Volo.CmsKit.Users;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Blogs;
public interface IBlogPostPublicAppService : IApplicationService
{
Task<PagedResultDto<BlogPostCommonDto>> GetListAsync(string blogSlug, BlogPostGetListInput input);
Task<BlogPostCommonDto> GetAsync(string blogSlug, string blogPostSlug);
Task<PagedResultDto<CmsUserDto>> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input);
Task<CmsUserDto> GetAuthorHasBlogPostAsync(Guid id);
Task DeleteAsync(Guid id);
Task<string> GetTagNameAsync(Guid tagId);
}

21
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CmsUserDto.cs

@ -0,0 +1,21 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Comments;
public class CmsUserDto : ExtensibleObject
{
public Guid Id { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}

33
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CommentDto.cs

@ -0,0 +1,33 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Comments;
public class CommentDto : ExtensibleObject
{
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; }
public string ConcurrencyStamp { get; set; }
public string Url { get; set; }
}

31
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CommentWithDetailsDto.cs

@ -0,0 +1,31 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Comments;
public class CommentWithDetailsDto : ExtensibleObject
{
public Guid Id { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public string Text { get; set; }
public Guid CreatorId { get; set; }
public DateTime CreationTime { get; set; }
public CommentDto[] Replies { get; set; }
public CmsUserDto Author { get; set; }
public string ConcurrencyStamp { get; set; }
}

25
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/CreateCommentInput.cs

@ -0,0 +1,25 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Comments;
public class CreateCommentInput : ExtensibleObject
{
public string Text { get; set; }
public Guid? RepliedCommentId { get; set; }
public Guid? CaptchaToken { get; set; }
public int CaptchaAnswer { get; set; }
public string Url { get; set; }
public string IdempotencyToken { get; set; }
}

22
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/ICommentPublicAppService.cs

@ -0,0 +1,22 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Public.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Comments;
public interface ICommentPublicAppService : IApplicationService
{
Task<ListResultDto<CommentWithDetailsDto>> GetListAsync(string entityType, string entityId);
Task<CommentDto> CreateAsync(string entityType, string entityId, CreateCommentInput input);
Task<CommentDto> UpdateAsync(Guid id, UpdateCommentInput input);
Task DeleteAsync(Guid id);
}

21
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Comments/UpdateCommentInput.cs

@ -0,0 +1,21 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Comments;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Comments;
public class UpdateCommentInput : ExtensibleObject
{
public string Text { get; set; }
public string ConcurrencyStamp { get; set; }
public Guid? CaptchaToken { get; set; }
public int CaptchaAnswer { get; set; }
}

17
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs

@ -0,0 +1,17 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.GlobalResources;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.GlobalResources;
public class GlobalResourceDto : ExtensibleAuditedEntityDto
{
public string Name { get; set; }
public string Value { get; set; }
}

18
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/GlobalResources/IGlobalResourcePublicAppService.cs

@ -0,0 +1,18 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Public.GlobalResources;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.GlobalResources;
public interface IGlobalResourcePublicAppService : IApplicationService
{
Task<GlobalResourceDto> GetGlobalScriptAsync();
Task<GlobalResourceDto> GetGlobalStyleAsync();
}

18
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/IMarkedItemPublicAppService.cs

@ -0,0 +1,18 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Public.MarkedItems;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.MarkedItems;
public interface IMarkedItemPublicAppService : IApplicationService
{
Task<MarkedItemWithToggleDto> GetForToggleAsync(string entityType, string entityId);
Task<bool> ToggleAsync(string entityType, string entityId);
}

15
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemDto.cs

@ -0,0 +1,15 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.MarkedItems;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.MarkedItems;
public class MarkedItemDto
{
public string IconName { get; set; }
}

37
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicClientProxy.Generated.cs

@ -0,0 +1,37 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Modeling;
using Volo.CmsKit.Public.MarkedItems;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.MarkedItems;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IMarkedItemPublicAppService), typeof(MarkedItemPublicClientProxy))]
public partial class MarkedItemPublicClientProxy : ClientProxyBase<IMarkedItemPublicAppService>, IMarkedItemPublicAppService
{
public virtual async Task<MarkedItemWithToggleDto> GetForToggleAsync(string entityType, string entityId)
{
return await RequestAsync<MarkedItemWithToggleDto>(nameof(GetForToggleAsync), new ClientProxyRequestTypeValue
{
{ typeof(string), entityType },
{ typeof(string), entityId }
});
}
public virtual async Task<bool> ToggleAsync(string entityType, string entityId)
{
return await RequestAsync<bool>(nameof(ToggleAsync), new ClientProxyRequestTypeValue
{
{ typeof(string), entityType },
{ typeof(string), entityId }
});
}
}

7
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicClientProxy.cs

@ -0,0 +1,7 @@
// This file is part of MarkedItemPublicClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.MarkedItems;
public partial class MarkedItemPublicClientProxy
{
}

17
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/MarkedItems/MarkedItemWithToggleDto.cs

@ -0,0 +1,17 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.MarkedItems;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.MarkedItems;
public class MarkedItemWithToggleDto
{
public MarkedItemDto MarkedItem { get; set; }
public bool IsMarkedByCurrentUser { get; set; }
}

17
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Menus/IMenuItemPublicAppService.cs

@ -0,0 +1,17 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Menus;
using Volo.CmsKit.Public.Menus;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Menus;
public interface IMenuItemPublicAppService : IApplicationService
{
Task<List<MenuItemDto>> GetListAsync();
}

21
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Pages/IPagePublicAppService.cs

@ -0,0 +1,21 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Contents;
using Volo.CmsKit.Public.Pages;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Pages;
public interface IPagePublicAppService : IApplicationService
{
Task<PageDto> FindBySlugAsync(string slug);
Task<bool> DoesSlugExistAsync(string slug);
Task<PageDto> FindDefaultHomePageAsync();
}

15
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/CreateUpdateRatingInput.cs

@ -0,0 +1,15 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Ratings;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Ratings;
public class CreateUpdateRatingInput
{
public Int16 StarCount { get; set; }
}

20
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/IRatingPublicAppService.cs

@ -0,0 +1,20 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Public.Ratings;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Ratings;
public interface IRatingPublicAppService : IApplicationService
{
Task<RatingDto> CreateAsync(string entityType, string entityId, CreateUpdateRatingInput input);
Task DeleteAsync(string entityType, string entityId);
Task<List<RatingWithStarCountDto>> GetGroupedStarCountsAsync(string entityType, string entityId);
}

25
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/RatingDto.cs

@ -0,0 +1,25 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Ratings;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Ratings;
public class RatingDto
{
public Guid Id { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public Int16 StarCount { get; set; }
public Guid CreatorId { get; set; }
public DateTime CreationTime { get; set; }
}

19
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Ratings/RatingWithStarCountDto.cs

@ -0,0 +1,19 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Ratings;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Ratings;
public class RatingWithStarCountDto
{
public Int16 StarCount { get; set; }
public int Count { get; set; }
public bool IsSelectedByCurrentUser { get; set; }
}

20
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Reactions/IReactionPublicAppService.cs

@ -0,0 +1,20 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Public.Reactions;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Reactions;
public interface IReactionPublicAppService : IApplicationService
{
Task<ListResultDto<ReactionWithSelectionDto>> GetForSelectionAsync(string entityType, string entityId);
Task CreateAsync(string entityType, string entityId, string reaction);
Task DeleteAsync(string entityType, string entityId, string reaction);
}

17
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Reactions/ReactionDto.cs

@ -0,0 +1,17 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Reactions;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Reactions;
public class ReactionDto
{
public string Name { get; set; }
public string DisplayName { get; set; }
}

19
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Reactions/ReactionWithSelectionDto.cs

@ -0,0 +1,19 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.ObjectExtending;
using Volo.CmsKit.Public.Reactions;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Reactions;
public class ReactionWithSelectionDto
{
public ReactionDto Reaction { get; set; }
public int Count { get; set; }
public bool IsSelectedByCurrentUser { get; set; }
}

18
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/Volo/CmsKit/Public/Tags/ITagAppService.cs

@ -0,0 +1,18 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.CmsKit.Tags;
// ReSharper disable once CheckNamespace
namespace Volo.CmsKit.Public.Tags;
public interface ITagAppService : IApplicationService
{
Task<List<TagDto>> GetAllRelatedTagsAsync(string entityType, string entityId);
Task<List<PopularTagDto>> GetPopularTagsAsync(string entityType, int maxCount);
}

8838
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json

File diff suppressed because it is too large

38
modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/MarkedItems/MarkedItemPublicController.cs

@ -0,0 +1,38 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.Features;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.Features;
using Volo.CmsKit.GlobalFeatures;
namespace Volo.CmsKit.Public.MarkedItems;
[RequiresFeature(CmsKitFeatures.MarkedItemEnable)]
[RequiresGlobalFeature(typeof(MarkedItemsFeature))]
[RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)]
[Area(CmsKitPublicRemoteServiceConsts.ModuleName)]
[Route("api/cms-kit-public/marked-items")]
public class MarkedItemPublicController : CmsKitPublicControllerBase, IMarkedItemPublicAppService
{
protected IMarkedItemPublicAppService MarkedItemPublicAppService { get; }
public MarkedItemPublicController(IMarkedItemPublicAppService markedItemPublicAppService)
{
MarkedItemPublicAppService = markedItemPublicAppService;
}
[HttpGet]
[Route("{entityType}/{entityId}")]
public virtual Task<MarkedItemWithToggleDto> GetForToggleAsync(string entityType, string entityId)
{
return MarkedItemPublicAppService.GetForToggleAsync(entityType, entityId);
}
[HttpPut]
[Route("{entityType}/{entityId}")]
public Task<bool> ToggleAsync(string entityType, string entityId)
{
return MarkedItemPublicAppService.ToggleAsync(entityType, entityId);
}
}

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

@ -13,10 +13,12 @@ using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.Localization; using Volo.CmsKit.Localization;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.Public.Web.Menus; using Volo.CmsKit.Public.Web.Menus;
using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Script; using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Script;
using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style; using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style;
using Volo.CmsKit.Web; using Volo.CmsKit.Web;
using Volo.CmsKit.Web.Icons;
namespace Volo.CmsKit.Public.Web; namespace Volo.CmsKit.Public.Web;
@ -46,6 +48,14 @@ public class CmsKitPublicWebModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
Configure<CmsKitUiOptions>(options =>
{
options.MarkedItemIcons[StandardMarkedItems.Favorite] = new LocalizableIconDictionary("fa fa-heart text-danger");
options.MarkedItemIcons[StandardMarkedItems.Flagged] = new LocalizableIconDictionary("fa fa-flag text-info");
options.MarkedItemIcons[StandardMarkedItems.Bookmark] = new LocalizableIconDictionary("fa fa-bookmark text-primary");
options.MarkedItemIcons[StandardMarkedItems.Starred] = new LocalizableIconDictionary("fa fa-star text-warning");
});
Configure<AbpNavigationOptions>(options => Configure<AbpNavigationOptions>(options =>
{ {
options.MenuContributors.Add(new CmsKitPublicMenuContributor()); options.MenuContributors.Add(new CmsKitPublicMenuContributor());

6
modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicWidgetsController.cs

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting; using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting;
using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.MarkedItemToggle;
using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating; using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating;
using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection; using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection;
@ -23,4 +24,9 @@ public class CmsKitPublicWidgetsController : CmsKitPublicControllerBase
{ {
return Task.FromResult((IActionResult)ViewComponent(typeof(RatingViewComponent), new { entityType, entityId })); return Task.FromResult((IActionResult)ViewComponent(typeof(RatingViewComponent), new { entityType, entityId }));
} }
public Task<IActionResult> MarkedItem(string entityType, string entityId, bool needsConfirmation)
{
return Task.FromResult((IActionResult)ViewComponent(typeof(MarkedItemToggleViewComponent), new { entityType, entityId, needsConfirmation }));
}
} }

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

@ -0,0 +1,14 @@
@using Volo.Abp.Users
@inject ICurrentUser CurrentUser
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.MarkedItemToggle.MarkedItemToggleViewComponent.MarkedItemToggleViewModel
@{
}
<div class="cms-markedItem-area"
data-entity-type="@Model.EntityType"
data-entity-id="@Model.EntityId"
data-needs-confirmation="@Model.NeedsConfirmation"
data-return-url="@(CurrentUser.IsAuthenticated ? "" : Model.ReturnUrl)">
<i class="cms-markedItem-icon @Model.MarkedItem.Icon @(Model.MarkedItem.IsMarkedByCurrentUser ? (Model.NeedsConfirmation ? "confirm" : "") : "unmarked")"
data-is-authenticated="@(CurrentUser.IsAuthenticated ? "true" : "false")"></i>
</div>

13
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/MarkedItemToggleScriptBundleContributor.cs

@ -0,0 +1,13 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.MarkedItemToggle;
public class MarkedItemToggleScriptBundleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/client-proxies/cms-kit-proxy.js");
context.Files.AddIfNotContains("/Pages/CmsKit/Shared/Components/MarkedItemToggle/default.js");
}
}

12
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/MarkedItemToggleStyleBundleContributor.cs

@ -0,0 +1,12 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.MarkedItemToggle;
public class MarkedItemToggleStyleBundleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/Pages/CmsKit/Shared/Components/MarkedItemToggle/default.css");
}
}

77
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/MarkedItemToggleViewComponent.cs

@ -0,0 +1,77 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
using Volo.CmsKit.Public.MarkedItems;
using Volo.CmsKit.Web;
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.MarkedItemToggle;
[ViewComponent(Name = "CmsMarkedItemToggle")]
[Widget(
ScriptTypes = new[] { typeof(MarkedItemToggleScriptBundleContributor) },
StyleTypes = new[] { typeof(MarkedItemToggleStyleBundleContributor) },
RefreshUrl = "/CmsKitPublicWidgets/MarkedItem",
AutoInitialize = true
)]
public class MarkedItemToggleViewComponent : AbpViewComponent
{
protected IMarkedItemPublicAppService MarkedItemPublicAppService { get; set; }
protected CmsKitUiOptions Options { get; }
public MarkedItemToggleViewComponent(
IMarkedItemPublicAppService markedItemPublicAppService,
IOptions<CmsKitUiOptions> options)
{
MarkedItemPublicAppService = markedItemPublicAppService;
Options = options.Value;
}
public virtual async Task<IViewComponentResult> InvokeAsync(
string entityType,
string entityId,
bool? needsConfirmation = false)
{
var result = await MarkedItemPublicAppService.GetForToggleAsync(entityType, entityId);
var returnUrl = HttpContext.Request.Path.ToString();
var viewModel = new MarkedItemToggleViewModel
{
EntityType = entityType,
EntityId = entityId,
NeedsConfirmation = needsConfirmation.GetValueOrDefault(),
MarkedItem = new MarkedItemViewModel()
{
Icon = Options.MarkedItemIcons.GetLocalizedIcon(result.MarkedItem.IconName),
IsMarkedByCurrentUser = result.IsMarkedByCurrentUser
},
ReturnUrl = returnUrl
};
return View("~/Pages/CmsKit/Shared/Components/MarkedItemToggle/Default.cshtml", viewModel);
}
public class MarkedItemToggleViewModel
{
public string EntityType { get; set; }
public string EntityId { get; set; }
public bool NeedsConfirmation { get; set; }
public MarkedItemViewModel MarkedItem { get; set; }
public string ReturnUrl { get; set; }
}
public class MarkedItemViewModel
{
[NotNull]
public string Icon { get; set; }
public bool IsMarkedByCurrentUser { get; set; }
}
}

7
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/default.css

@ -0,0 +1,7 @@
body {
}
.cms-markedItem-area i {
font-size: 1.5em;
cursor: pointer;
}

92
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/MarkedItemToggle/default.js

@ -0,0 +1,92 @@
(function ($) {
var l = abp.localization.getResource('CmsKit');
abp.widgets.CmsMarkedItemToggle = function ($widget) {
let widgetManager = $widget.data('abp-widget-manager');
let $markedItemArea = $widget.find('.cms-markedItem-area');
let loginModal = new abp.ModalManager(abp.appPath + 'CmsKit/Shared/Modals/Login/LoginModal');
function getFilters() {
return {
entityType: $markedItemArea.attr('data-entity-type'),
entityId: $markedItemArea.attr('data-entity-id'),
needsConfirmation: $markedItemArea.attr('data-needs-confirmation')
};
}
function setIconStyles($icon) {
var iconColor = $icon.css('color');
$icon.css({
'-webkit-text-stroke-color': iconColor,
'-webkit-text-stroke-width': '2px'
});
// Manually set the important rule for color
$icon[0].style.setProperty('color', 'transparent', 'important');
}
function isDoubleClicked(element) {
if (element.data("isclicked")) return true;
element.data("isclicked", true);
setTimeout(function () {
element.removeData("isclicked");
}, 500);
}
function handleUnauthenticated() {
loginModal.open({
message: l("CmsKit:MarkedItem:LoginMessage"),
returnUrl: $markedItemArea.attr('data-return-url')
});
}
function registerClickOfMarkedItemIcon($container) {
var $icon = $container.find('.cms-markedItem-icon');
if (isDoubleClicked($icon)) return;
$icon.click(async function () {
if ($icon.attr('data-is-authenticated') === 'false') {
handleUnauthenticated();
return;
}
if ($icon.hasClass('confirm') && !$icon.hasClass('unmarked')) {
const confirmed = await abp.message.confirm(l('CmsKit:MarkedItem:ToggleConfirmation'));
if (confirmed) {
toggleIcon($icon);
}
return;
}
else {
toggleIcon();
}
});
}
async function toggleIcon() {
await volo.cmsKit.public.markedItems.markedItemPublic.toggle(
$markedItemArea.attr('data-entity-type'),
$markedItemArea.attr('data-entity-id')
);
widgetManager.refresh($widget);
}
function init() {
var $unmarked = $widget.find('.unmarked');
if ($unmarked.length === 1) {
setIconStyles($unmarked);
}
registerClickOfMarkedItemIcon($widget);
}
return {
init: init,
getFilters: getFilters
};
};
})(jQuery);

22
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Modals/Login/LoginModal.cshtml

@ -0,0 +1,22 @@
@page
@using Microsoft.Extensions.Localization
@using Volo.CmsKit.Localization
@inject IStringLocalizer<CmsKitResource> L
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Modals.Login.LoginModalModel
@{
Layout = null;
var message = String.IsNullOrEmpty(Model.ViewModel.Message) ? L["CmsKit:Modals:LoginModalDefaultMessage"] : Model.ViewModel.Message;
}
<abp-modal centered="true">
<abp-modal-header title="@L["CmsKit:Modals:YouAreNotAuthenticated"]">
</abp-modal-header>
<abp-modal-body>
<div class="text-center">
<h4>
@message
</h4>
<br />
<a href="@Model.ViewModel.LoginUrl" class="btn btn-secondary">@L["CmsKit:Modals:Login"]</a>
</div>
</abp-modal-body>
</abp-modal>

32
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Modals/Login/LoginModal.cshtml.cs

@ -0,0 +1,32 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI;
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Modals.Login;
public class LoginModalModel : CmsKitPublicPageModelBase
{
public AbpMvcUiOptions AbpMvcUiOptions { get; }
public LoginModalViewModel ViewModel { get; set; }
public LoginModalModel(IOptions<AbpMvcUiOptions> abpMvcUiOptions)
{
AbpMvcUiOptions = abpMvcUiOptions.Value;
}
public void OnGet(string message, string? returnUrl = "")
{
ViewModel = new LoginModalViewModel
{
LoginUrl = $"{AbpMvcUiOptions.LoginUrl}?returnUrl={returnUrl}",
Message = message
};
}
}
public class LoginModalViewModel
{
[NotNull]
public string Message { get; set; }
public string LoginUrl { get; set; }
}

22
modules/cms-kit/src/Volo.CmsKit.Public.Web/wwwroot/client-proxies/cms-kit-proxy.js

@ -117,6 +117,28 @@
})(); })();
// controller volo.cmsKit.public.markedItems.markedItemPublic
(function(){
abp.utils.createNamespace(window, 'volo.cmsKit.public.markedItems.markedItemPublic');
volo.cmsKit.public.markedItems.markedItemPublic.getForToggle = function(entityType, entityId, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-public/marked-items/' + entityType + '/' + entityId + '',
type: 'GET'
}, ajaxParams));
};
volo.cmsKit.public.markedItems.markedItemPublic.toggle = function(entityType, entityId, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/cms-kit-public/marked-items/' + entityType + '/' + entityId + '',
type: 'PUT'
}, ajaxParams));
};
})();
// controller volo.cmsKit.public.menus.menuItemPublic // controller volo.cmsKit.public.menus.menuItemPublic
(function(){ (function(){

65
modules/cms-kit/test/Volo.CmsKit.Application.Tests/MarkedItems/MarkedItemPublicAppService_Tests.cs

@ -0,0 +1,65 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Shouldly;
using Volo.Abp.Users;
using Volo.CmsKit.Public.MarkedItems;
using Xunit;
namespace Volo.CmsKit.MarkedItems;
public class MarkedItemPublicAppService_Tests : CmsKitApplicationTestBase
{
private readonly CmsKitTestData _cmsKitTestData;
private readonly MarkedItemPublicAppService _markedItemPublicAppService;
private ICurrentUser _currentUser;
public MarkedItemPublicAppService_Tests()
{
_cmsKitTestData = GetRequiredService<CmsKitTestData>();
_markedItemPublicAppService = GetRequiredService<MarkedItemPublicAppService>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
_currentUser = Substitute.For<ICurrentUser>();
services.AddSingleton(_currentUser);
}
[Fact]
public async Task GetForToggleAsync()
{
_currentUser.Id.Returns(_cmsKitTestData.User1Id);
_currentUser.IsAuthenticated.Returns(true);
var firstMarkedItem = await _markedItemPublicAppService.GetForToggleAsync(
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId1
);
var secondMarkedItem = await _markedItemPublicAppService.GetForToggleAsync(
_cmsKitTestData.EntityType2,
_cmsKitTestData.EntityId1
);
firstMarkedItem.IsMarkedByCurrentUser.ShouldBeTrue();
secondMarkedItem.IsMarkedByCurrentUser.ShouldBeFalse();
}
[Fact]
public async Task ToggleAsync()
{
_currentUser.Id.Returns(_cmsKitTestData.User1Id);
var firstToggleResult = await _markedItemPublicAppService.ToggleAsync(
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId1
);
var secondToggleResult = await _markedItemPublicAppService.ToggleAsync(
_cmsKitTestData.EntityType2,
_cmsKitTestData.EntityId1
);
firstToggleResult.ShouldBeFalse();
secondToggleResult.ShouldBeTrue();
}
}

45
modules/cms-kit/test/Volo.CmsKit.Domain.Tests/MarkedItems/MarkedItemManager_Tests.cs

@ -0,0 +1,45 @@
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.CmsKit.MarkedItems;
public class MarkedItemManager_Tests : CmsKitDomainTestBase
{
private readonly CmsKitTestData _cmsKitTestData;
private readonly MarkedItemManager _markedItemManager;
public MarkedItemManager_Tests()
{
_cmsKitTestData = GetRequiredService<CmsKitTestData>();
_markedItemManager = GetRequiredService<MarkedItemManager>();
}
[Fact]
public async Task ToggleAsync()
{
var firstToggleResult = await _markedItemManager.ToggleAsync(
_cmsKitTestData.User1Id,
_cmsKitTestData.EntityType2,
_cmsKitTestData.EntityId1
);
var secondToggleResult = await _markedItemManager.ToggleAsync(
_cmsKitTestData.User1Id,
_cmsKitTestData.EntityType2,
_cmsKitTestData.EntityId1
);
firstToggleResult.ShouldBeTrue();
secondToggleResult.ShouldBeFalse();
}
[Fact]
public async Task GetAsync()
{
var markedItem = await _markedItemManager.GetAsync(_cmsKitTestData.EntityType1);
markedItem.EntityType.ShouldBe(_cmsKitTestData.EntityType1);
markedItem.IconName.ShouldBe(StandardMarkedItems.Favorite);
}
}

6
modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/MarkedItems/UserMarkedItemRepository_Tests.cs

@ -0,0 +1,6 @@
using Volo.CmsKit.MarkedItems;
namespace Volo.CmsKit.EntityFrameworkCore.MarkedItems;
public class UserMarkedItemRepository_Tests : UserMarkedItemRepository_Tests<CmsKitEntityFrameworkCoreTestModule>
{
}

9
modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/MarkedItems/UserMarkedItemRepository_Tests.cs

@ -0,0 +1,9 @@
using Volo.CmsKit.MarkedItems;
using Xunit;
namespace Volo.CmsKit.MongoDB.MarkedItems;
[Collection(MongoTestCollection.Name)]
public class UserMarkedItemRepository_Tests : UserMarkedItemRepository_Tests<CmsKitMongoDbTestModule>
{
}

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

@ -12,6 +12,7 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.Users; using Volo.Abp.Users;
using Volo.CmsKit.Blogs; using Volo.CmsKit.Blogs;
using Volo.CmsKit.Comments; using Volo.CmsKit.Comments;
using Volo.CmsKit.MarkedItems;
using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MediaDescriptors;
using Volo.CmsKit.Menus; using Volo.CmsKit.Menus;
using Volo.CmsKit.Pages; using Volo.CmsKit.Pages;
@ -49,6 +50,8 @@ public class CmsKitDataSeedContributor : IDataSeedContributor, ITransientDepende
private readonly IOptions<CmsKitCommentOptions> _commentsOptions; private readonly IOptions<CmsKitCommentOptions> _commentsOptions;
private readonly IOptions<CmsKitRatingOptions> _ratingOptions; private readonly IOptions<CmsKitRatingOptions> _ratingOptions;
private readonly IMenuItemRepository _menuItemRepository; private readonly IMenuItemRepository _menuItemRepository;
private readonly MarkedItemManager _markedItemManager;
private readonly IOptions<CmsKitMarkedItemOptions> _markedItemOptions;
public CmsKitDataSeedContributor( public CmsKitDataSeedContributor(
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
@ -75,7 +78,9 @@ public class CmsKitDataSeedContributor : IDataSeedContributor, ITransientDepende
IOptions<CmsKitMediaOptions> cmsMediaOptions, IOptions<CmsKitMediaOptions> cmsMediaOptions,
IOptions<CmsKitCommentOptions> commentsOptions, IOptions<CmsKitCommentOptions> commentsOptions,
IOptions<CmsKitRatingOptions> ratingOptions, IOptions<CmsKitRatingOptions> ratingOptions,
IMenuItemRepository menuItemRepository) IMenuItemRepository menuItemRepository,
MarkedItemManager markedItemManager,
IOptions<CmsKitMarkedItemOptions> markedItemOptions)
{ {
_guidGenerator = guidGenerator; _guidGenerator = guidGenerator;
_cmsUserRepository = cmsUserRepository; _cmsUserRepository = cmsUserRepository;
@ -102,6 +107,8 @@ public class CmsKitDataSeedContributor : IDataSeedContributor, ITransientDepende
_commentsOptions = commentsOptions; _commentsOptions = commentsOptions;
_ratingOptions = ratingOptions; _ratingOptions = ratingOptions;
_menuItemRepository = menuItemRepository; _menuItemRepository = menuItemRepository;
_markedItemManager = markedItemManager;
_markedItemOptions = markedItemOptions;
} }
public async Task SeedAsync(DataSeedContext context) public async Task SeedAsync(DataSeedContext context)
@ -129,6 +136,8 @@ public class CmsKitDataSeedContributor : IDataSeedContributor, ITransientDepende
await SeedMediaAsync(); await SeedMediaAsync();
await SeedMenusAsync(); await SeedMenusAsync();
await SeedMarkedItemsAsync();
} }
} }
@ -171,6 +180,9 @@ public class CmsKitDataSeedContributor : IDataSeedContributor, ITransientDepende
_ratingOptions.Value.EntityTypes.Add(new RatingEntityTypeDefinition(_cmsKitTestData.EntityType1)); _ratingOptions.Value.EntityTypes.Add(new RatingEntityTypeDefinition(_cmsKitTestData.EntityType1));
_ratingOptions.Value.EntityTypes.Add(new RatingEntityTypeDefinition(_cmsKitTestData.EntityType2)); _ratingOptions.Value.EntityTypes.Add(new RatingEntityTypeDefinition(_cmsKitTestData.EntityType2));
_markedItemOptions.Value.EntityTypes.Add(new MarkedItemEntityTypeDefinition(_cmsKitTestData.EntityType1, StandardMarkedItems.Favorite));
_markedItemOptions.Value.EntityTypes.Add(new MarkedItemEntityTypeDefinition(_cmsKitTestData.EntityType2, StandardMarkedItems.Starred));
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -442,4 +454,18 @@ public class CmsKitDataSeedContributor : IDataSeedContributor, ITransientDepende
menuItem4 menuItem4
}); });
} }
private async Task SeedMarkedItemsAsync()
{
await _markedItemManager.ToggleAsync(
_cmsKitTestData.User1Id,
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId1
);
await _markedItemManager.ToggleAsync(
_cmsKitTestData.User1Id,
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId2
);
}
} }

64
modules/cms-kit/test/Volo.CmsKit.TestBase/MarkedItems/UserMarkedItemRepository_Tests.cs

@ -0,0 +1,64 @@
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.CmsKit.MarkedItems;
public abstract class UserMarkedItemRepository_Tests<TStartupModule> : CmsKitTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly CmsKitTestData _cmsKitTestData;
private readonly IUserMarkedItemRepository _userMarkedItemRepository;
protected UserMarkedItemRepository_Tests()
{
_cmsKitTestData = GetRequiredService<CmsKitTestData>();
_userMarkedItemRepository = GetRequiredService<IUserMarkedItemRepository>();
}
[Fact]
public async Task FindAsync()
{
var markedItem = await _userMarkedItemRepository.FindAsync(
_cmsKitTestData.User1Id,
_cmsKitTestData.EntityType1,
_cmsKitTestData.EntityId1
);
markedItem.ShouldNotBeNull();
markedItem.CreatorId.ShouldBe(_cmsKitTestData.User1Id);
markedItem.EntityId.ShouldBe(_cmsKitTestData.EntityId1);
markedItem.EntityType.ShouldBe(_cmsKitTestData.EntityType1);
}
[Fact]
public async Task GetListForUserAsync()
{
var markedItems = await _userMarkedItemRepository.GetListForUserAsync(
_cmsKitTestData.User1Id,
_cmsKitTestData.EntityType1
);
markedItems.Count.ShouldBe(2);
}
[Fact]
public async Task GetQueryForUserAsync()
{
await WithUnitOfWorkAsync(async () =>
{
var query = await _userMarkedItemRepository.GetQueryForUserAsync(
_cmsKitTestData.EntityType1,
_cmsKitTestData.User1Id
);
var markedItems = query.ToList();
markedItems.Count.ShouldBe(2);
markedItems.All(x => x.CreatorId == _cmsKitTestData.User1Id).ShouldBeTrue();
markedItems.All(x => x.EntityType == _cmsKitTestData.EntityType1).ShouldBeTrue();
});
}
}
Loading…
Cancel
Save