From 52908a7496a7938144ab2f9a8a56225a59987e3b Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Tue, 28 Jul 2020 17:48:23 +0300 Subject: [PATCH] cmskit: commets initial files & backend --- .../Pages/Index.cshtml | 2 + .../Volo/CmsKit/Comments/CommentConsts.cs | 11 +++ .../Volo/CmsKit/Comments/Comment.cs | 50 ++++++++++ .../CmsKit/Comments/ICommentRepository.cs | 15 +++ .../Comments/EfCoreCommentRepository.cs | 50 ++++++++++ .../EntityFrameworkCore/CmsKitDbContext.cs | 3 + .../CmsKitDbContextModelCreatingExtensions.cs | 16 ++++ .../EntityFrameworkCore/ICmsKitDbContext.cs | 3 + .../Volo/CmsKit/Comments/CommentDto.cs | 21 +++++ .../CmsKit/Comments/CommentWithRepliesDto.cs | 22 +++++ .../CmsKit/Comments/CreateCommentInput.cs | 23 +++++ .../Comments/ICommentPublicAppService.cs | 19 ++++ .../CmsKit/Comments/UpdateCommentInput.cs | 13 +++ .../Comments/CommentPublicAppService.cs | 83 +++++++++++++++++ .../PublicApplicationAutoMapperProfile.cs | 7 +- .../Comments/CommentPublicController.cs | 48 ++++++++++ .../CommentingScriptBundleContributor.cs | 15 +++ .../CommentingStyleBundleContributor.cs | 13 +++ .../Commenting/CommentingViewComponent.cs | 92 +++++++++++++++++++ .../Components/Commenting/Default.cshtml | 22 +++++ .../Shared/Components/Commenting/default.css | 13 +++ .../Shared/Components/Commenting/default.js | 76 +++++++++++++++ 22 files changed, 616 insertions(+), 1 deletion(-) create mode 100644 modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Comments/CommentConsts.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentRepository.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentDto.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentWithRepliesDto.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CreateCommentInput.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/ICommentPublicAppService.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/UpdateCommentInput.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Comments/CommentPublicAppService.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Comments/CommentPublicController.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingScriptBundleContributor.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingStyleBundleContributor.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.css create mode 100644 modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml index 62ef15d4b7..a0d01ae300 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml @@ -2,6 +2,7 @@ @using Localization.Resources.AbpUi @using Microsoft.Extensions.Localization @using Volo.CmsKit.Pages +@using Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.Commenting @using Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.ReactionSelection @model IndexModel @inject IStringLocalizer Localizer @@ -23,6 +24,7 @@ @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new { entityType = "quote", entityId = "1" }) + @await Component.InvokeAsync(typeof(CommentingViewComponent), new { entityType = "quote", entityId = "1" }) diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Comments/CommentConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Comments/CommentConsts.cs new file mode 100644 index 0000000000..9fed054cae --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Comments/CommentConsts.cs @@ -0,0 +1,11 @@ +namespace Volo.CmsKit.Comments +{ + public static class CommentConsts + { + public static int EntityTypeLength { get; set; } = 64; + + public static int EntityIdLength { get; set; } = 64; + + public static int MaxTextLength { get; set; } = 512; + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs new file mode 100644 index 0000000000..fdcdfe37c2 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs @@ -0,0 +1,50 @@ +using System; +using JetBrains.Annotations; +using Volo.Abp; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; + +namespace Volo.CmsKit.Comments +{ + public class Comment: Entity, IAggregateRoot, IHasCreationTime, IMustHaveCreator + { + public virtual string EntityType { get; protected set; } + + public virtual string EntityId { get; protected set; } + + public virtual string Text { get; protected set; } + + public virtual Guid? RepliedCommentId { get; protected set; } + + public virtual Guid CreatorId { get; set; } + + public virtual DateTime CreationTime { get; set; } + + protected Comment() + { + + } + + public Comment( + Guid id, + [NotNull] string entityType, + [NotNull] string entityId, + [NotNull] string text, + Guid? repliedCommentId, + Guid creatorId) + : base(id) + { + EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType), CommentConsts.EntityTypeLength); + EntityId = Check.NotNullOrWhiteSpace(entityId, nameof(entityId), CommentConsts.EntityIdLength); + RepliedCommentId = repliedCommentId; + CreatorId = creatorId; + + SetText(text); + } + + public virtual void SetText(string text) + { + Text = Check.NotNullOrWhiteSpace(text, nameof(text), CommentConsts.MaxTextLength); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentRepository.cs new file mode 100644 index 0000000000..a189c8938e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentRepository.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Domain.Repositories; + +namespace Volo.CmsKit.Comments +{ + public interface ICommentRepository : IBasicRepository + { + Task> GetListAsync( + [NotNull] string entityType, + [NotNull] string entityId); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs new file mode 100644 index 0000000000..42e9de4f32 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; + +namespace Volo.CmsKit.Comments +{ + public class EfCoreCommentRepository : EfCoreRepository, + ICommentRepository + { + public EfCoreCommentRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task> GetListAsync( + string entityType, + string entityId) + { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); + + return await DbSet + .Where(x => + x.EntityType == entityType && + x.EntityId == entityId) + .ToListAsync(); + } + + public override async Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default) + { + var replies = await DbSet + .Where(x => x.RepliedCommentId == id) + .ToListAsync(GetCancellationToken(cancellationToken)); + + foreach (var reply in replies) + { + await base.DeleteAsync(reply.Id, autoSave, GetCancellationToken(cancellationToken)); + } + + await base.DeleteAsync(id, autoSave, GetCancellationToken(cancellationToken)); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs index e90e133d7f..01384a3aa1 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.Comments; using Volo.CmsKit.Reactions; namespace Volo.CmsKit.EntityFrameworkCore @@ -10,6 +11,8 @@ namespace Volo.CmsKit.EntityFrameworkCore { public DbSet UserReactions { get; set; } + public DbSet Comments { get; set; } + public CmsKitDbContext(DbContextOptions options) : base(options) { diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs index 9eeb191f5b..e551412d5e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp; using Volo.Abp.EntityFrameworkCore.Modeling; +using Volo.CmsKit.Comments; using Volo.CmsKit.Reactions; namespace Volo.CmsKit.EntityFrameworkCore @@ -34,6 +35,21 @@ namespace Volo.CmsKit.EntityFrameworkCore b.HasIndex(x => new { x.EntityType, x.EntityId }); b.HasIndex(x => new { x.CreatorId, x.EntityType, x.EntityId, x.ReactionName }); }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "Comments", options.Schema); + b.ConfigureByConvention(); + + b.Property(x => x.EntityType).IsRequired().HasMaxLength(CommentConsts.EntityTypeLength); + b.Property(x => x.EntityId).IsRequired().HasMaxLength(CommentConsts.EntityIdLength); + b.Property(x => x.Text).IsRequired().HasMaxLength(CommentConsts.MaxTextLength); + b.Property(x => x.RepliedCommentId); + b.Property(x => x.CreationTime); + + b.HasIndex(x => new { x.EntityType, x.EntityId }); + b.HasIndex(x => new { x.RepliedCommentId }); + }); } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs index 9441986b23..ecd807d005 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.Comments; using Volo.CmsKit.Reactions; namespace Volo.CmsKit.EntityFrameworkCore @@ -9,5 +10,7 @@ namespace Volo.CmsKit.EntityFrameworkCore public interface ICmsKitDbContext : IEfCoreDbContext { DbSet UserReactions { get; } + + DbSet Comments { get; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentDto.cs new file mode 100644 index 0000000000..0852bab22e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentDto.cs @@ -0,0 +1,21 @@ +using System; + +namespace Volo.CmsKit.Comments +{ + public class CommentDto + { + public Guid Id { get; set; } + + public string EntityType { get; set; } + + public string EntityId { get; set; } + + public string Text { get; set; } + + public Guid? RepliedCommentId { get; set; } + + public Guid CreatorId { get; set; } + + public DateTime CreationTime { get; set; } + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentWithRepliesDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentWithRepliesDto.cs new file mode 100644 index 0000000000..a9e682f856 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CommentWithRepliesDto.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace Volo.CmsKit.Comments +{ + public class CommentWithRepliesDto + { + 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 List Replies { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CreateCommentInput.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CreateCommentInput.cs new file mode 100644 index 0000000000..30b86b75f0 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/CreateCommentInput.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace Volo.CmsKit.Comments +{ + public class CreateCommentInput + { + [Required] + [DynamicStringLength(typeof(CommentConsts), nameof(CommentConsts.EntityTypeLength))] + public string EntityType { get; set; } + + [Required] + [DynamicStringLength(typeof(CommentConsts), nameof(CommentConsts.EntityIdLength))] + public string EntityId { get; set; } + + [Required] + [DynamicStringLength(typeof(CommentConsts), nameof(CommentConsts.MaxTextLength))] + public string Text { get; set; } + + public Guid? RepliedCommentId { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/ICommentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/ICommentPublicAppService.cs new file mode 100644 index 0000000000..bffe742aca --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/ICommentPublicAppService.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Application.Services; + +namespace Volo.CmsKit.Comments +{ + public interface ICommentPublicAppService : IApplicationService + { + Task> GetAllForEntityAsync(string entityType, string entityId); + + Task CreateAsync(CreateCommentInput input); + + Task UpdateAsync(Guid id, UpdateCommentInput input); + + Task DeleteAsync(Guid id); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/UpdateCommentInput.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/UpdateCommentInput.cs new file mode 100644 index 0000000000..e084914626 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Comments/UpdateCommentInput.cs @@ -0,0 +1,13 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace Volo.CmsKit.Comments +{ + public class UpdateCommentInput + { + [Required] + [DynamicStringLength(typeof(CommentConsts), nameof(CommentConsts.MaxTextLength))] + public string Text { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Comments/CommentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Comments/CommentPublicAppService.cs new file mode 100644 index 0000000000..7833460f0d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Comments/CommentPublicAppService.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Volo.Abp; +using Volo.Abp.Application.Services; + +namespace Volo.CmsKit.Comments +{ + [Authorize] + public class CommentPublicAppService : ApplicationService, ICommentPublicAppService + { + protected ICommentRepository CommentRepository { get; } + + public CommentPublicAppService(ICommentRepository commentRepository) + { + CommentRepository = commentRepository; + } + + public async Task> GetAllForEntityAsync(string entityType, string entityId) + { + var comments = await CommentRepository.GetListAsync(entityType, entityId); + + return ConvertCommentsToNestedStructure(comments); + } + + public async Task CreateAsync(CreateCommentInput input) + { + var comment = await CommentRepository.InsertAsync(new Comment( + GuidGenerator.Create(), + input.EntityType, + input.EntityId, + input.Text, + input.RepliedCommentId, + CurrentUser.Id.Value + )); + + return ObjectMapper.Map(comment); + } + + public async Task UpdateAsync(Guid id, UpdateCommentInput input) + { + var comment = await CommentRepository.GetAsync(id); + + comment.SetText(input.Text); + + var updatedComment = await CommentRepository.UpdateAsync(comment); + + return ObjectMapper.Map(updatedComment); + } + + public async Task DeleteAsync(Guid id) + { + var comment = await CommentRepository.GetAsync(id); + + if (comment.CreatorId != CurrentUser.Id) + { + throw new BusinessException(); + } + + await CommentRepository.DeleteAsync(id); + } + + private List ConvertCommentsToNestedStructure(List comments) + { + var parentComments = comments + .Where(c=> c.RepliedCommentId == null) + .Select(c=> ObjectMapper.Map(c)) + .ToList(); + + foreach (var parentComment in parentComments) + { + parentComment.Replies = comments + .Where(c => c.RepliedCommentId == parentComment.Id) + .Select(c => ObjectMapper.Map(c)) + .ToList(); + } + + return parentComments; + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/PublicApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/PublicApplicationAutoMapperProfile.cs index e88dd5c4b3..695bb8376c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/PublicApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/PublicApplicationAutoMapperProfile.cs @@ -1,4 +1,6 @@ using AutoMapper; +using Volo.Abp.AutoMapper; +using Volo.CmsKit.Comments; namespace Volo.CmsKit { @@ -9,6 +11,9 @@ namespace Volo.CmsKit /* You can configure your AutoMapper mapping configuration here. * Alternatively, you can split your mapping configurations * into multiple profile classes for a better organization. */ + + CreateMap(); + CreateMap().Ignore(x=> x.Replies); } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Comments/CommentPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Comments/CommentPublicController.cs new file mode 100644 index 0000000000..cc5cedb309 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Comments/CommentPublicController.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; + +namespace Volo.CmsKit.Comments +{ + [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] + [Area("cms-kit")] + [Route("api/cms-kit-public/comments")] + public class CommentPublicController : CmsKitPublicControllerBase, ICommentPublicAppService + { + public ICommentPublicAppService CommentPublicAppService { get; } + + public CommentPublicController(ICommentPublicAppService commentPublicAppService) + { + CommentPublicAppService = commentPublicAppService; + } + + [HttpGet] + [Route("{entityType}/{entityId}")] + public Task> GetAllForEntityAsync(string entityType, string entityId) + { + return CommentPublicAppService.GetAllForEntityAsync(entityType, entityId); + } + + [HttpPost] + public Task CreateAsync(CreateCommentInput input) + { + return CommentPublicAppService.CreateAsync(input); + } + + [HttpPost] + [Route("{id}")] + public Task UpdateAsync(Guid id, UpdateCommentInput input) + { + return CommentPublicAppService.UpdateAsync(id, input); + } + + [HttpDelete] + [Route("update")] + public Task DeleteAsync(Guid id) + { + return CommentPublicAppService.DeleteAsync(id); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingScriptBundleContributor.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingScriptBundleContributor.cs new file mode 100644 index 0000000000..8f1b6ad38e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingScriptBundleContributor.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; +using Volo.Abp.AspNetCore.Mvc.UI.Packages.Bootstrap; +using Volo.Abp.Modularity; + +namespace Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.Commenting +{ + public class CommentingScriptBundleContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files.AddIfNotContains("/Pages/CmsKit/Shared/Components/Commenting/default.js"); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingStyleBundleContributor.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingStyleBundleContributor.cs new file mode 100644 index 0000000000..158c8e15d2 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingStyleBundleContributor.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; + +namespace Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.Commenting +{ + public class CommentingStyleBundleContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files.AddIfNotContains("/Pages/CmsKit/Shared/Components/Commenting/default.css"); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs new file mode 100644 index 0000000000..d73174c1dc --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +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.Reactions; + +namespace Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.Commenting +{ + [ViewComponent(Name = "CmsCommenting")] + [Widget( + ScriptTypes = new[] {typeof(CommentingScriptBundleContributor)}, + StyleTypes = new[] {typeof(CommentingStyleBundleContributor)}, + RefreshUrl = "/CmsKitPublicWidgets/Commenting" + )] + public class CommentingViewComponent : AbpViewComponent + { + protected IReactionPublicAppService ReactionPublicAppService { get; } + + protected CmsKitUiOptions Options { get; } + + public CommentingViewComponent( + IReactionPublicAppService reactionPublicAppService, + IOptions options) + { + } + + public virtual async Task InvokeAsync( + string entityType, + string entityId) + { + + return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", new CommentingViewModel + { + EntityType = entityType, + EntityId = entityId, + Reactions = new List() + }); + + var result = await ReactionPublicAppService.GetForSelectionAsync(entityType, entityId); + + var viewModel = new CommentingViewModel + { + EntityType = entityType, + EntityId = entityId, + Reactions = new List() + }; + + foreach (var reactionDto in result.Items) + { + viewModel.Reactions.Add( + new CommentViewModel //TODO: AutoMap + { + Name = reactionDto.Reaction.Name, + DisplayName = reactionDto.Reaction.DisplayName, + Icon = Options.ReactionIcons.GetLocalizedIcon(reactionDto.Reaction.Name), + Count = reactionDto.Count, + IsSelectedByCurrentUser = reactionDto.IsSelectedByCurrentUser + }); + } + + return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", viewModel); + } + + public class CommentingViewModel + { + public string EntityType { get; set; } + + public string EntityId { get; set; } + + public List Reactions { get; set; } + } + + public class CommentViewModel + { + [NotNull] + public string Name { get; set; } + + [CanBeNull] + public string DisplayName { get; set; } + + [NotNull] + public string Icon { get; set; } + + public int Count { get; set; } + + public bool IsSelectedByCurrentUser { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml new file mode 100644 index 0000000000..af2f1d2fea --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml @@ -0,0 +1,22 @@ +@model Volo.CmsKit.Web.Pages.CmsKit.Shared.Components.Commenting.CommentingViewComponent.CommentingViewModel +
+
+
Yunus Emre Kalkan
+

+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. + Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, + when an unknown printer took a galley of type and scrambled it to make a type specimen book. + It has survived not only five centuries, but also the leap into electronic typesetting. +

+
+
+
+
Yunus Emre Kalkan
+

+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. + Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, + when an unknown printer took a galley of type and scrambled it to make a type specimen book. + It has survived not only five centuries, but also the leap into electronic typesetting. +

+
+
diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.css new file mode 100644 index 0000000000..8e27846c5c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.css @@ -0,0 +1,13 @@ +.cms-reaction-select-icon +{ + cursor: pointer; +} +.cms-reaction-icon +{ + cursor: pointer; + padding: 3px 5px 5px; +} +.cms-reaction-icon-selected +{ + background-color: #eef; +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js new file mode 100644 index 0000000000..543e56e216 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.js @@ -0,0 +1,76 @@ +(function ($) { + + /* + var l = abp.localization.getResource('CmsKit'); + + var myDefaultWhiteList = $.fn.tooltip.Constructor.Default.whiteList; + + if (myDefaultWhiteList.span.indexOf('data-reaction-name') < 0) { + myDefaultWhiteList.span.push('data-reaction-name'); + } + + $(document).ready(function () { + + abp.widgets.CmsReactionSelection = function ($widget) { + var widgetManager = $widget.data('abp-widget-manager'); + var $reactionArea = $widget.find('.cms-reaction-area'); + var $selectIcon = $widget.find('.cms-reaction-select-icon'); + var $popoverContent = $widget.find('.cms-reaction-selection-popover-content'); + + function getFilters() { + return { + entityType: $reactionArea.attr('data-entity-type'), + entityId: $reactionArea.attr('data-entity-id') + }; + } + + function registerClickOfReactionIcons($container) { + $container.find('.cms-reaction-icon').each(function () { + var $icon = $(this); + $icon.click(function () { + var methodName = $icon.hasClass('cms-reaction-icon-selected') ? 'delete' : 'create'; + volo.cmsKit.reactions.reactionPublic[methodName]( + $.extend(getFilters(), { + reactionName: $icon.attr('data-reaction-name') + }) + ).then(function () { + $selectIcon.popover('hide'); + widgetManager.refresh($widget); + }); + }); + }); + } + + function init() { + + $selectIcon.popover({ + placement: 'right', + html: true, + trigger: 'focus', + title: l('PickYourReaction'), + content: $popoverContent.html() + }).on('shown.bs.popover', function () { + var $popover = $('#' + $selectIcon.attr('aria-describedby')); + registerClickOfReactionIcons($popover); + }); + + registerClickOfReactionIcons($widget); + } + + return { + init: init, + getFilters: getFilters + }; + }; + + $('.abp-widget-wrapper[data-widget-name="CmsCommenting"]') + .each(function () { + var widgetManager = new abp.WidgetManager({ + wrapper: $(this), + }); + + widgetManager.init(); + }); + }); + */ +})(jQuery);