mirror of https://github.com/abpframework/abp.git
Browse Source
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
87 changed files with 10988 additions and 262 deletions
@ -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: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
|
||||
|
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. |
||||
|
|
||||
|
 |
||||
|
|
||||
|
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** |
||||
|
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 483 KiB |
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
using Volo.CmsKit.Web.Icons; |
||||
|
|
||||
|
namespace Volo.CmsKit.Web.MarkedItems; |
||||
|
|
||||
|
public class MarkedItemIconDictionary : LocalizableIconDictionaryBase |
||||
|
{ |
||||
|
} |
||||
@ -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); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
@ -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." |
||||
|
} |
||||
} |
} |
||||
@ -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"; |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.CmsKit.MarkedItems; |
||||
|
|
||||
|
public interface IMarkedItemDefinitionStore : IEntityTypeDefinitionStore<MarkedItemEntityTypeDefinition> |
||||
|
{ |
||||
|
} |
||||
@ -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 |
||||
|
); |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.CmsKit.Public.MarkedItems; |
||||
|
|
||||
|
[Serializable] |
||||
|
public class MarkedItemDto |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string IconName { get; set; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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 |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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 } |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
{ |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
File diff suppressed because it is too large
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -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> |
||||
@ -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"); |
||||
|
} |
||||
|
} |
||||
@ -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"); |
||||
|
} |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
body { |
||||
|
} |
||||
|
|
||||
|
.cms-markedItem-area i { |
||||
|
font-size: 1.5em; |
||||
|
cursor: pointer; |
||||
|
} |
||||
@ -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); |
||||
@ -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> |
||||
@ -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; } |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
using Volo.CmsKit.MarkedItems; |
||||
|
|
||||
|
namespace Volo.CmsKit.EntityFrameworkCore.MarkedItems; |
||||
|
public class UserMarkedItemRepository_Tests : UserMarkedItemRepository_Tests<CmsKitEntityFrameworkCoreTestModule> |
||||
|
{ |
||||
|
} |
||||
@ -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> |
||||
|
{ |
||||
|
} |
||||
@ -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…
Reference in new issue