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 index 81fd94406d..eb05b77926 100644 --- 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 @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -7,6 +8,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI; using Volo.Abp.AspNetCore.Mvc.UI.Widgets; +using Volo.CmsKit.Public.Application.Security.VoloCaptcha; using Volo.CmsKit.Public.Comments; using Volo.CmsKit.Web.Renderers; @@ -24,15 +26,31 @@ public class CommentingViewComponent : AbpViewComponent public ICommentPublicAppService CommentPublicAppService { get; } public IMarkdownToHtmlRenderer MarkdownToHtmlRenderer { get; } public AbpMvcUiOptions AbpMvcUiOptions { get; } + public SimpleMathsCaptchaGenerator SimpleMathsCaptchaGenerator { get; } + + [HiddenInput] + [BindProperty] + public string RecaptchaToken { get; set; } + + [HiddenInput] + [BindProperty] + public Guid CaptchaId { get; set; } + + [BindProperty] + public CommentingViewModel Input { get; set; } + + public CaptchaOutput CaptchaOutput { get; set; } public CommentingViewComponent( ICommentPublicAppService commentPublicAppService, IOptions options, - IMarkdownToHtmlRenderer markdownToHtmlRenderer) + IMarkdownToHtmlRenderer markdownToHtmlRenderer, + SimpleMathsCaptchaGenerator simpleMathsCaptchaGenerator) { CommentPublicAppService = commentPublicAppService; MarkdownToHtmlRenderer = markdownToHtmlRenderer; AbpMvcUiOptions = options.Value; + SimpleMathsCaptchaGenerator = simpleMathsCaptchaGenerator; } public virtual async Task InvokeAsync( @@ -42,7 +60,6 @@ public class CommentingViewComponent : AbpViewComponent var comments = (await CommentPublicAppService .GetListAsync(entityType, entityId)).Items; - var loginUrl = $"{AbpMvcUiOptions.LoginUrl}?returnUrl={HttpContext.Request.Path.ToString()}&returnUrlHash=#cms-comment_{entityType}_{entityId}"; var viewModel = new CommentingViewModel @@ -52,10 +69,23 @@ public class CommentingViewComponent : AbpViewComponent LoginUrl = loginUrl, Comments = comments.OrderByDescending(i => i.CreationTime).ToList() }; - await ConvertMarkdownTextsToHtml(viewModel); - return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", viewModel); + CaptchaOutput = SimpleMathsCaptchaGenerator.Generate(new CaptchaOptions( + number1MinValue: 1, + number1MaxValue: 10, + number2MinValue: 5, + number2MaxValue: 15) + ); + + viewModel.CaptchaImageBase64 = GetCaptchaImageBase64(CaptchaOutput.ImageBytes); + this.Input = viewModel; + return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", this); + } + + private string GetCaptchaImageBase64(byte[] bytes) + { + return $"data:image/jpg;base64,{Convert.ToBase64String(bytes)}"; } private async Task ConvertMarkdownTextsToHtml(CommentingViewModel viewModel) @@ -86,6 +116,15 @@ public class CommentingViewComponent : AbpViewComponent public IReadOnlyList Comments { get; set; } public Dictionary RawCommentTexts { get; set; } + + [Required] + [StringLength(100, MinimumLength = 1)] + public string Captcha { get; set; } + + public string CaptchaImageBase64 { 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 index 9d0438098d..3814ef755f 100644 --- 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 @@ -11,7 +11,7 @@ @inject ICurrentUser CurrentUser @inject IOptionsSnapshot cmsKitUiOptions; @inject IHtmlLocalizer L -@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting.CommentingViewComponent.CommentingViewModel +@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting.CommentingViewComponent @{ Func GetCommentTitle(CmsUserDto author, DateTime creationTime) => @@ -36,9 +36,26 @@ + + +
+ +
+
+ +
+
+ +
+ + +
+
+ +
- + @L["Send"] @if (cancelButton) @@ -71,13 +88,13 @@ { @if (CurrentUser.IsAuthenticated) { - + @L["Reply"] } else { - @L["LoginToReply"] + @L["LoginToReply"] } } @if (authorId == CurrentUser.Id) @@ -93,9 +110,10 @@ } @{ Func GetEditArea(Guid id, string text, string concurrencyStamp) => - @ }
+ 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 index 469c8274f6..8d241afcd5 100644 --- 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 @@ -3,4 +3,28 @@ } .comment-links:hover { text-decoration: none; -} \ No newline at end of file +} +body .volo-captcha img { + border: 1px outset #dddcdc; + border-radius: 4px; + height: 45px; +} + +body .volo-captcha .d-flex .form-group { + width: 100%; +} + +@media (max-width: 800px) { + body .volo-captcha #Input_Captcha { + margin-left: 0px; + } +} + +body .form-control { + border: 1px outset #e3e3e3 !important; + padding: 10px !important; +} + +body #submit-button { + margin-top: 10px; +} 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 index a4fca33947..3b98f1f7ec 100644 --- 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 @@ -1,10 +1,10 @@ (function ($) { - var l = abp.localization.getResource('CmsKit'); + let l = abp.localization.getResource('CmsKit'); abp.widgets.CmsCommenting = function ($widget) { - var widgetManager = $widget.data('abp-widget-manager'); - var $commentArea = $widget.find('.cms-comment-area'); + let widgetManager = $widget.data('abp-widget-manager'); + let $commentArea = $widget.find('.cms-comment-area'); function getFilters() { return { @@ -15,14 +15,14 @@ function registerEditLinks($container) { $container.find('.comment-edit-link').each(function () { - var $link = $(this); + let $link = $(this); $link.on('click', function (e) { e.preventDefault(); - var commentId = $link.data('id'); + let commentId = $link.data('id'); - var $relatedCommentContentArea = $container.find('.cms-comment-content-area[data-id=' + commentId + ']'); - var $relatedCommentEditFormArea = $container.find('.cms-comment-edit-area[data-id=' + commentId + ']'); + let $relatedCommentContentArea = $container.find('.cms-comment-content-area[data-id=' + commentId + ']'); + let $relatedCommentEditFormArea = $container.find('.cms-comment-edit-area[data-id=' + commentId + ']'); $relatedCommentContentArea.hide(); $relatedCommentEditFormArea.show(); @@ -30,15 +30,15 @@ }); }); $container.find('.comment-edit-cancel-button').each(function () { - var $button = $(this); + let $button = $(this); $button.on('click', function (e) { e.preventDefault(); - var commentId = $button.data('id'); + let commentId = $button.data('id'); - var $relatedCommentContentArea = $container.find('.cms-comment-content-area[data-id=' + commentId + ']'); - var $relatedCommentEditFormArea = $container.find('.cms-comment-edit-area[data-id=' + commentId + ']'); - var $link = $container.find('.comment-edit-link[data-id=' + commentId + ']'); + let $relatedCommentContentArea = $container.find('.cms-comment-content-area[data-id=' + commentId + ']'); + let $relatedCommentEditFormArea = $container.find('.cms-comment-edit-area[data-id=' + commentId + ']'); + let $link = $container.find('.comment-edit-link[data-id=' + commentId + ']'); $relatedCommentContentArea.show(); $relatedCommentEditFormArea.hide(); @@ -49,14 +49,14 @@ function registerReplyLinks($container) { $container.find('.comment-reply-link').each(function () { - var $link = $(this); + let $link = $(this); $link.on('click', function (e) { e.preventDefault(); - var replyCommentId = $link.data('reply-id'); + let replyCommentId = $link.data('reply-id'); - var $relatedCommentArea = $container.find('.cms-comment-form-area[data-reply-id=' + replyCommentId + ']'); - var $links = $container.find('.comment-reply-link[data-reply-id=' + replyCommentId + ']'); + let $relatedCommentArea = $container.find('.cms-comment-form-area[data-reply-id=' + replyCommentId + ']'); + let $links = $container.find('.comment-reply-link[data-reply-id=' + replyCommentId + ']'); $relatedCommentArea.show(); $relatedCommentArea.find('textarea').focus(); @@ -64,14 +64,14 @@ }); }); $container.find('.reply-cancel-button').each(function () { - var $button = $(this); + let $button = $(this); $button.on('click', function (e) { e.preventDefault(); - var replyCommentId = $button.data('reply-id'); + let replyCommentId = $button.data('reply-id'); - var $relatedCommentArea = $container.find('.cms-comment-form-area[data-reply-id=' + replyCommentId + ']'); - var $links = $container.find('.comment-reply-link[data-reply-id=' + replyCommentId + ']'); + let $relatedCommentArea = $container.find('.cms-comment-form-area[data-reply-id=' + replyCommentId + ']'); + let $links = $container.find('.comment-reply-link[data-reply-id=' + replyCommentId + ']'); $relatedCommentArea.hide(); $links.removeClass('disabled'); @@ -81,7 +81,7 @@ function registerDeleteLinks($container) { $container.find('.comment-delete-link').each(function () { - var $link = $(this); + let $link = $(this); $link.on('click', '', function (e) { e.preventDefault(); @@ -99,10 +99,10 @@ function registerUpdateOfNewComment($container) { $container.find('.cms-comment-update-form').each(function () { - var $form = $(this); + let $form = $(this); $form.submit(function (e) { e.preventDefault(); - var formAsObject = $form.serializeFormToObject(); + let formAsObject = $form.serializeFormToObject(); volo.cmsKit.public.comments.commentPublic.update( formAsObject.id, { @@ -118,21 +118,22 @@ function registerSubmissionOfNewComment($container) { $container.find('.cms-comment-form').each(function () { - var $form = $(this); + let $form = $(this); $form.submit(function (e) { e.preventDefault(); - var formAsObject = $form.serializeFormToObject(); + let formAsObject = $form.serializeFormToObject(); - if (formAsObject.repliedCommentId == ''){ + if (formAsObject.repliedCommentId == '') { formAsObject.repliedCommentId = null; } - volo.cmsKit.public.comments.commentPublic.create( $commentArea.attr('data-entity-type'), $commentArea.attr('data-entity-id'), { repliedCommentId: formAsObject.repliedCommentId, - text: formAsObject.commentText + text: formAsObject.commentText, + captchaToken: formAsObject.captchaId, + captchaAnswer: formAsObject.input.captcha } ).then(function () { widgetManager.refresh($widget); @@ -146,7 +147,7 @@ return; } - var $link = $(location.hash + '_link'); + let $link = $(location.hash + '_link'); if ($link.length > 0) { $link.click(); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.scss b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.scss new file mode 100644 index 0000000000..82d41f9795 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/default.scss @@ -0,0 +1,30 @@ +body { + .volo-captcha { + img { + border: 1px outset #dddcdc; + border-radius: 4px; + height: 45px; + } + + .d-flex { + .form-group { + width: 100%; + } + } + + @media (max-width: 800px) { + #Input_Captcha { + margin-left: 0px; + } + } + } + + .form-control { + border: 1px outset #e3e3e3 !important; + padding: 10px !important; + } + + #submit-button { + margin-top: 10px; + } +}