CommentController.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. using Hangfire;
  2. using Masuit.MyBlogs.Core.Common;
  3. using Masuit.MyBlogs.Core.Extensions;
  4. using Masuit.MyBlogs.Core.Infrastructure.Services.Interface;
  5. using Masuit.MyBlogs.Core.Models.DTO;
  6. using Masuit.MyBlogs.Core.Models.Entity;
  7. using Masuit.MyBlogs.Core.Models.Enum;
  8. using Masuit.MyBlogs.Core.Models.ViewModel;
  9. using Masuit.Tools;
  10. using Masuit.Tools.Core.Net;
  11. using Masuit.Tools.Html;
  12. using Microsoft.AspNetCore.Hosting;
  13. using Microsoft.AspNetCore.Http;
  14. using Microsoft.AspNetCore.Mvc;
  15. using Microsoft.EntityFrameworkCore.Internal;
  16. using Microsoft.Net.Http.Headers;
  17. using System;
  18. using System.Collections.Generic;
  19. using System.IO;
  20. using System.Linq;
  21. using System.Text.RegularExpressions;
  22. namespace Masuit.MyBlogs.Core.Controllers
  23. {
  24. /// <summary>
  25. /// 评论管理
  26. /// </summary>
  27. public class CommentController : BaseController
  28. {
  29. public ICommentService CommentService { get; set; }
  30. public IPostService PostService { get; set; }
  31. public IInternalMessageService MessageService { get; set; }
  32. public IWebHostEnvironment HostEnvironment { get; set; }
  33. /// <summary>
  34. /// 发表评论
  35. /// </summary>
  36. /// <param name="dto"></param>
  37. /// <returns></returns>
  38. [HttpPost, ValidateAntiForgeryToken]
  39. public ActionResult Put(CommentInputDto dto)
  40. {
  41. if (Regex.Match(dto.Content, CommonHelper.BanRegex).Length > 0)
  42. {
  43. return ResultData(null, false, "您提交的内容包含敏感词,被禁止发表,请检查您的内容后尝试重新提交!");
  44. }
  45. Post post = PostService.GetById(dto.PostId);
  46. if (post is null)
  47. {
  48. return ResultData(null, false, "评论失败,文章不存在!");
  49. }
  50. if (post.DisableComment)
  51. {
  52. return ResultData(null, false, "本文已禁用评论功能,不允许任何人回复!");
  53. }
  54. dto.Content = dto.Content.Trim().Replace("<p><br></p>", string.Empty);
  55. if (dto.Content.RemoveHtmlTag().Trim().Equals(HttpContext.Session.Get<string>("comment" + dto.PostId)))
  56. {
  57. return ResultData(null, false, "您刚才已经在这篇文章发表过一次评论了,换一篇文章吧,或者换一下评论内容吧!");
  58. }
  59. var comment = dto.Mapper<Comment>();
  60. if (Regex.Match(dto.Content, CommonHelper.ModRegex).Length <= 0)
  61. {
  62. comment.Status = Status.Pended;
  63. }
  64. comment.CommentDate = DateTime.Now;
  65. var user = HttpContext.Session.Get<UserInfoOutputDto>(SessionKey.UserInfo);
  66. if (user != null)
  67. {
  68. comment.NickName = user.NickName;
  69. comment.QQorWechat = user.QQorWechat;
  70. comment.Email = user.Email;
  71. if (user.IsAdmin)
  72. {
  73. comment.Status = Status.Pended;
  74. comment.IsMaster = true;
  75. }
  76. }
  77. comment.Content = dto.Content.HtmlSantinizerStandard().ClearImgAttributes();
  78. comment.Browser = dto.Browser ?? Request.Headers[HeaderNames.UserAgent];
  79. comment.IP = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
  80. comment.Location = comment.IP.GetIPLocation().Split("|").Where(s => !int.TryParse(s, out _)).ToHashSet().Join("|");
  81. comment = CommentService.AddEntitySaved(comment);
  82. if (comment == null)
  83. {
  84. return ResultData(null, false, "评论失败");
  85. }
  86. HttpContext.Session.Set("comment" + comment.PostId, comment.Content.RemoveHtmlTag().Trim());
  87. var emails = new HashSet<string>();
  88. var email = CommonHelper.SystemSettings["ReceiveEmail"]; //站长邮箱
  89. emails.Add(email);
  90. var content = System.IO.File.ReadAllText(HostEnvironment.WebRootPath + "/template/notify.html")
  91. .Replace("{{title}}", post.Title)
  92. .Replace("{{time}}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
  93. .Replace("{{nickname}}", comment.NickName)
  94. .Replace("{{content}}", comment.Content);
  95. if (comment.Status == Status.Pended)
  96. {
  97. if (!comment.IsMaster)
  98. {
  99. MessageService.AddEntitySaved(new InternalMessage()
  100. {
  101. Title = $"来自【{comment.NickName}】的新文章评论",
  102. Content = comment.Content,
  103. Link = Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment"
  104. });
  105. }
  106. #if !DEBUG
  107. if (comment.ParentId == 0)
  108. {
  109. emails.Add(post.Email);
  110. emails.Add(post.ModifierEmail);
  111. //新评论,只通知博主和楼主
  112. foreach (var s in emails)
  113. {
  114. BackgroundJob.Enqueue(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Domain"] + "|博客文章新评论:", content.Replace("{{link}}", Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment"), s));
  115. }
  116. }
  117. else
  118. {
  119. //通知博主和上层所有关联的评论访客
  120. var pid = CommentService.GetParentCommentIdByChildId(comment.Id);
  121. emails.AddRange(CommentService.GetSelfAndAllChildrenCommentsByParentId(pid).Select(c => c.Email).ToArray());
  122. emails.AddRange(post.Email, post.ModifierEmail);
  123. emails.Remove(comment.Email);
  124. string link = Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment";
  125. foreach (var s in emails)
  126. {
  127. BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{CommonHelper.SystemSettings["Domain"]}{CommonHelper.SystemSettings["Title"]}文章评论回复:", content.Replace("{{link}}", link), s));
  128. }
  129. }
  130. #endif
  131. return ResultData(null, true, "评论发表成功,服务器正在后台处理中,这会有一定的延迟,稍后将显示到评论列表中");
  132. }
  133. foreach (var s in emails)
  134. {
  135. BackgroundJob.Enqueue(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Domain"] + "|博客文章新评论(待审核):", content.Replace("{{link}}", Url.Action("Details", "Post", new { id = comment.PostId, cid = comment.Id }, Request.Scheme) + "#comment") + "<p style='color:red;'>(待审核)</p>", s));
  136. }
  137. return ResultData(null, true, "评论成功,待站长审核通过以后将显示");
  138. }
  139. /// <summary>
  140. /// 评论投票
  141. /// </summary>
  142. /// <param name="id"></param>
  143. /// <returns></returns>
  144. [HttpPost]
  145. public ActionResult CommentVote(int id)
  146. {
  147. Comment cm = CommentService.Get(c => c.Id == id && c.Status == Status.Pended);
  148. if (HttpContext.Session.Get("cm" + id) != null)
  149. {
  150. return ResultData(null, false, "您刚才已经投过票了,感谢您的参与!");
  151. }
  152. if (cm == null)
  153. {
  154. return ResultData(null, false, "非法操作");
  155. }
  156. cm.VoteCount++;
  157. HttpContext.Session.Set("cm" + id, id.GetBytes());
  158. bool b = CommentService.SaveChanges() > 0;
  159. return ResultData(null, b, b ? "投票成功" : "投票失败");
  160. }
  161. /// <summary>
  162. /// 获取评论
  163. /// </summary>
  164. /// <param name="id"></param>
  165. /// <param name="page"></param>
  166. /// <param name="size"></param>
  167. /// <param name="cid"></param>
  168. /// <returns></returns>
  169. [HttpPost]
  170. public ActionResult GetComments(int? id, int page = 1, int size = 5, int cid = 0)
  171. {
  172. int total; //总条数,用于前台分页
  173. if (cid != 0)
  174. {
  175. int pid = CommentService.GetParentCommentIdByChildId(cid);
  176. var single = CommentService.GetSelfAndAllChildrenCommentsByParentId(pid).ToList();
  177. if (single.Any())
  178. {
  179. total = 1;
  180. return ResultData(new
  181. {
  182. total,
  183. parentTotal = total,
  184. page,
  185. size,
  186. rows = single.Mapper<IList<CommentViewModel>>()
  187. });
  188. }
  189. }
  190. var parent = CommentService.GetPagesFromCache(page, size, out total, c => c.PostId == id && c.ParentId == 0 && (c.Status == Status.Pended || CurrentUser.IsAdmin), c => c.CommentDate, false).ToList();
  191. if (!parent.Any())
  192. {
  193. return ResultData(null, false, "没有评论");
  194. }
  195. parent = parent.SelectMany(c => CommentService.GetSelfAndAllChildrenCommentsByParentId(c.Id).Where(x => (x.Status == Status.Pended || CurrentUser.IsAdmin))).ToList();
  196. if (total > 0)
  197. {
  198. return ResultData(new
  199. {
  200. total,
  201. parentTotal = total,
  202. page,
  203. size,
  204. rows = parent.Mapper<IList<CommentViewModel>>()
  205. });
  206. }
  207. return ResultData(null, false, "没有评论");
  208. }
  209. /// <summary>
  210. /// 审核评论
  211. /// </summary>
  212. /// <param name="id"></param>
  213. /// <returns></returns>
  214. [Authority]
  215. public ActionResult Pass(int id)
  216. {
  217. Comment comment = CommentService.GetById(id);
  218. comment.Status = Status.Pended;
  219. Post post = PostService.GetById(comment.PostId);
  220. bool b = CommentService.SaveChanges() > 0;
  221. if (b)
  222. {
  223. var pid = comment.ParentId == 0 ? comment.Id : CommentService.GetParentCommentIdByChildId(id);
  224. #if !DEBUG
  225. var content = System.IO.File.ReadAllText(Path.Combine(HostEnvironment.WebRootPath, "template", "notify.html"))
  226. .Replace("{{title}}", post.Title)
  227. .Replace("{{time}}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
  228. .Replace("{{nickname}}", comment.NickName)
  229. .Replace("{{content}}", comment.Content);
  230. var emails = CommentService.GetSelfAndAllChildrenCommentsByParentId(pid).Select(c => c.Email).Append(post.ModifierEmail).Except(new List<string> { comment.Email, CurrentUser.Email }).ToHashSet();
  231. var link = Url.Action("Details", "Post", new
  232. {
  233. id = comment.PostId,
  234. cid = pid
  235. }, Request.Scheme) + "#comment";
  236. foreach (var email in emails)
  237. {
  238. BackgroundJob.Enqueue(() => CommonHelper.SendMail($"{Request.Host}{CommonHelper.SystemSettings["Title"]}文章评论回复:", content.Replace("{{link}}", link), email));
  239. }
  240. #endif
  241. return ResultData(null, true, "审核通过!");
  242. }
  243. return ResultData(null, false, "审核失败!");
  244. }
  245. /// <summary>
  246. /// 删除评论
  247. /// </summary>
  248. /// <param name="id"></param>
  249. /// <returns></returns>
  250. [Authority]
  251. public ActionResult Delete(int id)
  252. {
  253. var b = CommentService.DeleteEntitiesSaved(CommentService.GetSelfAndAllChildrenCommentsByParentId(id).ToList());
  254. return ResultData(null, b, b ? "删除成功!" : "删除失败!");
  255. }
  256. /// <summary>
  257. /// 获取未审核的评论
  258. /// </summary>
  259. /// <returns></returns>
  260. [Authority]
  261. public ActionResult GetPendingComments(int page = 1, int size = 10)
  262. {
  263. var list = CommentService.GetPages<DateTime, CommentOutputDto>(page, size, out int total, c => c.Status == Status.Pending, c => c.CommentDate, false).ToList();
  264. var pageCount = Math.Ceiling(total * 1.0 / size).ToInt32();
  265. return PageResult(list, pageCount, total);
  266. }
  267. }
  268. }