using AutoMapper;
using Common;
using EFSecondLevelCache.Core;
using Hangfire;
using Masuit.LuceneEFCore.SearchEngine.Interfaces;
using Masuit.MyBlogs.Core.Common;
using Masuit.MyBlogs.Core.Configs;
using Masuit.MyBlogs.Core.Extensions;
using Masuit.MyBlogs.Core.Extensions.Hangfire;
using Masuit.MyBlogs.Core.Infrastructure;
using Masuit.MyBlogs.Core.Infrastructure.Services.Interface;
using Masuit.MyBlogs.Core.Models.DTO;
using Masuit.MyBlogs.Core.Models.Entity;
using Masuit.MyBlogs.Core.Models.Enum;
using Masuit.MyBlogs.Core.Models.ViewModel;
using Masuit.Tools;
using Masuit.Tools.Core.Net;
using Masuit.Tools.DateTimeExt;
using Masuit.Tools.Html;
using Masuit.Tools.Security;
using Masuit.Tools.Systems;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Net.Http.Headers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Masuit.MyBlogs.Core.Controllers
{
///
/// 文章管理
///
public class PostController : BaseController
{
private IPostService PostService { get; set; }
private ICategoryService CategoryService { get; set; }
private IBroadcastService BroadcastService { get; set; }
private ISeminarService SeminarService { get; set; }
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ISearchEngine _searchEngine;
///
///
///
public IPostHistoryVersionService PostHistoryVersionService { get; set; }
///
/// 文章管理
///
///
///
///
///
///
///
///
public PostController(IPostService postService, ICategoryService categoryService, IBroadcastService broadcastService, ISeminarService seminarService, IPostHistoryVersionService postHistoryVersionService, IHostingEnvironment hostingEnvironment, ISearchEngine searchEngine)
{
PostService = postService;
CategoryService = categoryService;
BroadcastService = broadcastService;
SeminarService = seminarService;
PostHistoryVersionService = postHistoryVersionService;
_hostingEnvironment = hostingEnvironment;
_searchEngine = searchEngine;
}
///
/// 文章详情页
///
///
///
///
[Route("{id:int}/{kw}"), Route("{id:int}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "kw" }, VaryByHeader = HeaderNames.Cookie)]
public ActionResult Details(int id, string kw)
{
Post post = PostService.GetById(id);
if (post != null)
{
ViewBag.Keyword = post.Keyword + "," + post.Label;
UserInfoOutputDto user = HttpContext.Session.Get(SessionKey.UserInfo) ?? new UserInfoOutputDto();
DateTime modifyDate = post.ModifyDate;
ViewBag.Next = PostService.GetFirstEntityNoTracking(p => p.ModifyDate > modifyDate && (p.Status == Status.Pended || user.IsAdmin), p => p.ModifyDate);
ViewBag.Prev = PostService.GetFirstEntityNoTracking(p => p.ModifyDate < modifyDate && (p.Status == Status.Pended || user.IsAdmin), p => p.ModifyDate, false);
if (!string.IsNullOrEmpty(kw))
{
ViewData["keywords"] = post.Content.Contains(kw) ? $"['{kw}']" : _searchEngine.LuceneIndexSearcher.CutKeywords(kw).ToJsonString();
}
if (user.IsAdmin)
{
return View("Details_Admin", post);
}
if (post.Status != Status.Pended)
{
return RedirectToAction("Post", "Home");
}
if (!HttpContext.Request.IsRobot() && string.IsNullOrEmpty(HttpContext.Session.Get("post" + id)))
{
HangfireHelper.CreateJob(typeof(IHangfireBackJob), nameof(HangfireBackJob.RecordPostVisit), args: id);
HttpContext.Session.Set("post" + id, id.ToString());
}
return View(post);
}
return RedirectToAction("Index", "Error");
}
///
/// 文章历史版本
///
///
///
///
///
[Route("{id:int}/history"), Route("{id:int}/history/{page:int}/{size:int}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "page", "size" }, VaryByHeader = HeaderNames.Cookie)]
public ActionResult History(int id, int page = 1, int size = 20)
{
var p = PostService.GetById(id).Mapper();
if (p != null)
{
ViewBag.Primary = p;
var list = PostHistoryVersionService.LoadPageEntitiesNoTracking(page, size, out int total, v => v.PostId == id, v => v.ModifyDate, false).Select(v => new PostHistoryVersion()
{
PostId = id,
Category = v.Category,
ModifyDate = v.ModifyDate,
Title = v.Title,
Id = v.Id,
CategoryId = v.CategoryId
}).Cacheable().ToList();
ViewBag.Total = total;
ViewBag.PageCount = Math.Ceiling(total * 1.0 / size).ToInt32();
return View(list);
}
return RedirectToAction("Details", "Post", new { id });
}
///
/// 文章历史版本
///
///
///
///
[Route("{id:int}/history/{hid:int}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "hid" }, VaryByHeader = HeaderNames.Cookie)]
public ActionResult HistoryVersion(int id, int hid)
{
UserInfoOutputDto user = HttpContext.Session.Get(SessionKey.UserInfo) ?? new UserInfoOutputDto();
var post = PostHistoryVersionService.GetById(hid);
if (post is null)
{
return RedirectToAction("History", new
{
id
});
}
ViewBag.Next = PostHistoryVersionService.GetFirstEntityNoTracking(p => p.PostId == id && p.ModifyDate > post.ModifyDate, p => p.ModifyDate);
ViewBag.Prev = PostHistoryVersionService.GetFirstEntityNoTracking(p => p.PostId == id && p.ModifyDate < post.ModifyDate, p => p.ModifyDate, false);
if (user.IsAdmin)
{
return View("HistoryVersion_Admin", post);
}
return View(post);
}
///
/// 版本对比
///
///
///
///
///
[Route("{id:int}/history/{v1:int}-{v2:int}"), ResponseCache(Duration = 600, VaryByQueryKeys = new[] { "id", "v1", "v2" }, VaryByHeader = HeaderNames.Cookie)]
public ActionResult CompareVersion(int id, int v1, int v2)
{
var main = PostService.GetById(id).Mapper();
var left = v1 <= 0 ? main : PostHistoryVersionService.GetById(v1);
var right = v2 <= 0 ? main : PostHistoryVersionService.GetById(v2);
if (left is null || right is null)
{
return RedirectToAction("History", "Post", new { id });
}
HtmlDiff.HtmlDiff diffHelper = new HtmlDiff.HtmlDiff(right.Content, left.Content);
string diffOutput = diffHelper.Build();
right.Content = Regex.Replace(Regex.Replace(diffOutput, "", string.Empty), @"<\w+>\w+>", string.Empty);
left.Content = Regex.Replace(Regex.Replace(diffOutput, "", string.Empty), @"<\w+>\w+>", string.Empty);
return View(new[]
{
main,
left,
right
});
}
///
/// 反对
///
///
///
public ActionResult VoteDown(int id)
{
Post post = PostService.GetById(id);
if (HttpContext.Session.Get("post-vote" + id) != null)
{
return ResultData(null, false, "您刚才已经投过票了,感谢您的参与!");
}
if (post != null)
{
HttpContext.Session.Set("post-vote" + id, id.GetBytes());
++post.VoteDownCount;
PostService.UpdateEntity(post);
var b = PostService.SaveChanges() > 0;
return ResultData(null, b, b ? "投票成功!" : "投票失败!");
}
return ResultData(null, false, "非法操作");
}
///
/// 支持
///
///
///
public ActionResult VoteUp(int id)
{
Post post = PostService.GetById(id);
if (HttpContext.Session.Get("post-vote" + id) != null)
{
return ResultData(null, false, "您刚才已经投过票了,感谢您的参与!");
}
if (post != null)
{
HttpContext.Session.Set("post-vote" + id, id.GetBytes());
++post.VoteUpCount;
PostService.UpdateEntity(post);
var b = PostService.SaveChanges() > 0;
return ResultData(null, b, b ? "投票成功!" : "投票失败!");
}
return ResultData(null, false, "非法操作");
}
///
/// 投稿页
///
///
public ActionResult Publish()
{
List list = PostService.GetAll().Select(p => p.Label).ToList();
List result = new List();
list.ForEach(s =>
{
if (!string.IsNullOrEmpty(s))
{
result.AddRange(s.Split(',', ','));
}
});
ViewBag.Category = CategoryService.LoadEntitiesNoTracking(c => c.Status == Status.Available).ToList();
UserInfoOutputDto user = HttpContext.Session.Get(SessionKey.UserInfo);
if (user != null)
{
return View("Publish_Admin", result.Distinct().OrderBy(s => s));
}
return View(result.Distinct().OrderBy(s => s));
}
///
/// 发布投稿
///
///
///
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Publish(PostInputDto post)
{
if (Regex.Match(post.Content, CommonHelper.BanRegex).Length > 0)
{
return ResultData(null, false, "您提交的内容包含敏感词,被禁止发表,请注意改善您的言辞!");
}
UserInfoOutputDto user = HttpContext.Session.Get(SessionKey.UserInfo);
if (!CategoryService.Any(c => c.Id == post.CategoryId && c.Status == Status.Available))
{
return ResultData(null, message: "请选择一个分类");
}
if (string.IsNullOrEmpty(post.Label?.Trim()))
{
post.Label = null;
}
else if (post.Label.Trim().Length > 50)
{
post.Label = post.Label.Replace(",", ",").Trim().Substring(0, 50);
}
else
{
post.Label = post.Label.Replace(",", ",");
}
post.Status = Status.Pending;
post.PostDate = DateTime.Now;
post.ModifyDate = DateTime.Now;
if (user != null && user.IsAdmin)
{
post.Status = Status.Pended;
}
else
{
post.Content = CommonHelper.ReplaceImgSrc(Regex.Replace(post.Content.HtmlSantinizerStandard(), @"
]*\s*src\s*=\s*['""]?(\S+\.\w{3,4})['""]?[^/>]*/>", "
")).Replace("/thumb150/", "/large/");
}
ViewBag.CategoryId = new SelectList(CategoryService.LoadEntitiesNoTracking(c => c.Status == Status.Available), "Id", "Name", post.CategoryId);
Post p = post.Mapper();
p.IP = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
p.PostAccessRecord.Add(new PostAccessRecord()
{
AccessTime = DateTime.Today,
ClickCount = 0
});
p = PostService.AddEntitySaved(p);
if (p != null)
{
if (p.Status == Status.Pending)
{
var email = CommonHelper.SystemSettings["ReceiveEmail"];
string link = Url.Action("Details", "Post", new
{
id = p.Id
}, Request.Scheme);
string content = System.IO.File.ReadAllText(_hostingEnvironment.WebRootPath + "/template/publish.html").Replace("{{link}}", link).Replace("{{time}}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")).Replace("{{title}}", p.Title);
BackgroundJob.Enqueue(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Title"] + "有访客投稿:", content, email));
return ResultData(p.Mapper(), message: "文章发表成功,待站长审核通过以后将显示到列表中!");
}
return ResultData(p.Mapper(), message: "文章发表成功!");
}
return ResultData(null, false, "文章发表失败!");
}
///
/// 获取标签
///
///
[ResponseCache(Duration = 600, VaryByHeader = HeaderNames.Cookie)]
public ActionResult GetTag()
{
List list = PostService.GetAll().Select(p => p.Label).ToList();
List result = new List();
list.ForEach(s =>
{
if (!string.IsNullOrEmpty(s))
{
result.AddRange(s.Split(',', ','));
}
});
return ResultData(result.Distinct().OrderBy(s => s));
}
///
/// 标签云
///
///
[Route("all"), ResponseCache(Duration = 600, VaryByHeader = HeaderNames.Cookie)]
public ActionResult All()
{
UserInfoOutputDto user = HttpContext.Session.Get(SessionKey.UserInfo) ?? new UserInfoOutputDto();
List tags = PostService.GetAll().Select(p => p.Label).ToList(); //tag
List result = new List();
tags.ForEach(s =>
{
if (!string.IsNullOrEmpty(s))
{
result.AddRange(s.Split(',', ','));
}
});
ViewBag.tags = result.GroupBy(t => t).OrderByDescending(g => g.Count()).ThenBy(g => g.Key);
ViewBag.cats = CategoryService.GetAll(c => c.Post.Count, false).Select(c => new TagCloudViewModel()
{
Id = c.Id,
Name = c.Name,
Count = c.Post.Count(p => p.Status == Status.Pended || user.IsAdmin)
}).ToList(); //category
ViewBag.seminars = SeminarService.GetAll(c => c.Post.Count, false).Select(c => new TagCloudViewModel
{
Id = c.Id,
Name = c.Title,
Count = c.Post.Count(p => p.Post.Status == Status.Pended || user.IsAdmin)
}).ToList(); //seminars
return View();
}
///
/// 检查访问密码
///
///
///
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CheckViewToken(string token)
{
if (string.IsNullOrEmpty(token))
{
return ResultData(null, false, "请输入文章访问密码!");
}
var s = RedisHelper.Get("ArticleViewToken");
if (token.Equals(s))
{
HttpContext.Session.Set("ArticleViewToken", token);
return ResultData(null);
}
return ResultData(null, false, "文章访问密码不正确!");
}
///
/// 检查授权邮箱
///
///
///
[HttpPost, ValidateAntiForgeryToken, ResponseCache(Duration = 120, VaryByQueryKeys = new[] { "email" })]
public ActionResult GetViewToken(string email)
{
if (string.IsNullOrEmpty(email) && !email.MatchEmail())
{
return ResultData(null, false, "请输入正确的邮箱!");
}
if (RedisHelper.Exists("code:" + email))
{
RedisHelper.Expire("code:" + email, 120);
return ResultData(null, false, "发送频率限制,请在2分钟后重新尝试发送邮件!请检查你的邮件,若未收到,请检查你的邮箱地址或邮件垃圾箱!");
}
if (BroadcastService.Any(b => b.Email.Equals(email) && b.SubscribeType == SubscribeType.ArticleToken))
{
var s = RedisHelper.Get("ArticleViewToken");
CommonHelper.SendMail(CommonHelper.SystemSettings["Domain"] + "博客文章验证码", $"{CommonHelper.SystemSettings["Domain"]}博客文章验证码是:{s},有效期为24h,请按时使用!", email);
RedisHelper.Set("code:" + email, s, 120);
return ResultData(null);
}
return ResultData(null, false, "您目前没有权限访问这篇文章的加密部分,请联系站长开通这篇文章的访问权限!");
}
#region 后端管理
///
/// 固顶
///
///
///
[Authority]
public ActionResult Fixtop(int id)
{
Post post = PostService.GetById(id);
post.IsFixedTop = !post.IsFixedTop;
bool b = PostService.UpdateEntitySaved(post);
if (b)
{
return ResultData(null, true, post.IsFixedTop ? "置顶成功!" : "取消置顶成功!");
}
return ResultData(null, false, "操作失败!");
}
///
/// 审核
///
///
///
[Authority]
public ActionResult Pass(int id)
{
Post post = PostService.GetById(id);
post.Status = Status.Pended;
post.ModifyDate = DateTime.Now;
post.PostDate = DateTime.Now;
bool b = PostService.UpdateEntitySaved(post);
if (!b)
{
return ResultData(null, false, "审核失败!");
}
if ("false" == CommonHelper.SystemSettings["DisabledEmailBroadcast"])
{
var cast = BroadcastService.LoadEntities(c => c.Status == Status.Subscribed).ToList();
string link = Request.Scheme + "://" + Request.Host + "/" + id;
cast.ForEach(c =>
{
var ts = DateTime.Now.GetTotalMilliseconds();
string content = System.IO.File.ReadAllText(_hostingEnvironment.WebRootPath + "/template/broadcast.html").Replace("{{link}}", link + "?email=" + c.Email).Replace("{{time}}", post.ModifyDate.ToString("yyyy-MM-dd HH:mm:ss")).Replace("{{title}}", post.Title).Replace("{{author}}", post.Author).Replace("{{content}}", post.Content.RemoveHtmlTag(150)).Replace("{{cancel}}", Url.Action("Subscribe", "Subscribe", new
{
c.Email,
act = "cancel",
validate = c.ValidateCode,
timespan = ts,
hash = (c.Email + "cancel" + c.ValidateCode + ts).AESEncrypt(AppConfig.BaiduAK)
}, Request.Scheme));
BackgroundJob.Enqueue(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Title"] + "博客有新文章发布了", content, c.Email));
});
}
return ResultData(null, true, "审核通过!");
}
///
/// 删除
///
///
///
[Authority]
public ActionResult Delete(int id)
{
var post = PostService.GetById(id);
post.Status = Status.Deleted;
bool b = PostService.UpdateEntitySaved(post);
_searchEngine.LuceneIndexer.Delete(post);
return ResultData(null, b, b ? "删除成功!" : "删除失败!");
}
///
/// 还原版本
///
///
///
[Authority]
public ActionResult Restore(int id)
{
var post = PostService.GetById(id);
post.Status = Status.Pended;
bool b = PostService.UpdateEntitySaved(post);
return ResultData(null, b, b ? "恢复成功!" : "恢复失败!");
}
///
/// 彻底删除文章
///
///
///
[Authority]
public ActionResult Truncate(int id)
{
var post = PostService.GetById(id);
if (post is null)
{
return ResultData(null, false, "文章已经被删除!");
}
if (post.IsWordDocument)
{
try
{
System.IO.File.Delete(Path.Combine(_hostingEnvironment.WebRootPath + "/upload", post.ResourceName));
Directory.Delete(Path.Combine(_hostingEnvironment.WebRootPath + "/upload", Path.GetFileNameWithoutExtension(post.ResourceName)), true);
}
catch (IOException)
{
}
}
var srcs = post.Content.MatchImgSrcs();
foreach (var path in srcs)
{
if (path.StartsWith("/"))
{
try
{
System.IO.File.Delete(_hostingEnvironment.WebRootPath + path);
}
catch (IOException)
{
}
}
}
bool b = PostService.DeleteByIdSaved(id);
return ResultData(null, b, b ? "删除成功!" : "删除失败!");
}
///
/// 获取文章
///
///
///
[Authority]
public ActionResult Get(int id)
{
Post post = PostService.GetById(id);
PostOutputDto model = post.Mapper();
model.Seminars = string.Join(",", post.Seminar.Select(s => s.Seminar.Title));
return ResultData(model);
}
///
/// 文章详情
///
///
///
[Authority]
public ActionResult Read(int id) => ResultData(PostService.GetById(id).Mapper());
///
/// 获取所有文章
///
///
public ActionResult GetAllData()
{
var plist = PostService.LoadEntitiesNoTracking(p => p.Status != Status.Deleted).OrderBy(p => p.Status).ThenByDescending(p => p.IsFixedTop).ThenByDescending(p => p.ModifyDate).Select(p => new
{
p.Id,
p.Author,
CategoryName = p.Category.Name,
p.Email,
p.IsFixedTop,
p.Label,
md = p.ModifyDate,
pd = p.PostDate,
p.Title,
ViewCount = p.TotalViewCount,
p.VoteDownCount,
p.VoteUpCount,
stat = p.Status
}).ToList();
var list = new List();
plist.ForEach(item =>
{
PostDataModel model = item.MapTo();
model.PostDate = item.pd.ToString("yyyy-MM-dd HH:mm");
model.ModifyDate = item.md.ToString("yyyy-MM-dd HH:mm");
model.Status = item.stat.GetDisplay();
list.Add(model);
});
return ResultData(list);
}
///
/// 获取文章分页
///
///
public ActionResult GetPageData(int page = 1, int size = 10, OrderBy orderby = OrderBy.ModifyDate, string kw = "")
{
if (page < 1)
{
page = 1;
}
if (size < 1)
{
page = 10;
}
var list = new List();
IOrderedQueryable temp;
var query = string.IsNullOrEmpty(kw) ? PostService.GetAllNoTracking() : PostService.LoadEntitiesNoTracking(p => p.Title.Contains(kw) || p.Author.Contains(kw) || p.Email.Contains(kw) || p.Label.Contains(kw) || p.Content.Contains(kw));
var total = query.Count();
var order = query.OrderByDescending(p => p.Status).ThenByDescending(p => p.IsFixedTop);
switch (orderby)
{
case OrderBy.CommentCount:
temp = order.ThenByDescending(p => p.Comment.Count);
break;
case OrderBy.PostDate:
temp = order.ThenByDescending(p => p.PostDate);
break;
case OrderBy.ViewCount:
temp = order.ThenByDescending(p => p.TotalViewCount);
break;
case OrderBy.VoteCount:
temp = order.ThenByDescending(p => p.VoteUpCount);
break;
case OrderBy.AverageViewCount:
temp = order.ThenByDescending(p => p.AverageViewCount);
break;
default:
temp = order.ThenByDescending(p => p.ModifyDate);
break;
}
var plist = temp.Skip((page - 1) * size).Take(size).Select(p => new
{
p.Id,
p.Author,
CategoryName = p.Category.Name,
p.Email,
p.IsFixedTop,
p.Label,
md = p.ModifyDate,
pd = p.PostDate,
p.Title,
ViewCount = p.TotalViewCount,
p.VoteDownCount,
p.VoteUpCount,
stat = p.Status,
ModifyCount = p.PostHistoryVersion.Count
}).ToList();
plist.ForEach(item =>
{
PostDataModel model = item.MapTo();
model.PostDate = item.pd.ToString("yyyy-MM-dd HH:mm");
model.ModifyDate = item.md.ToString("yyyy-MM-dd HH:mm");
model.Status = item.stat.GetDisplay();
model.ModifyCount = item.ModifyCount;
list.Add(model);
});
var pageCount = Math.Ceiling(total * 1.0 / size).ToInt32();
return PageResult(list, pageCount, total);
}
///
/// 获取未审核文章
///
///
///
///
///
[Authority]
public ActionResult GetPending(int page = 1, int size = 10, string search = "")
{
int total;
IQueryable temp;
if (string.IsNullOrEmpty(search))
{
temp = PostService.LoadPageEntitiesNoTracking(page, size, out total, p => p.Status == Status.Pending, p => p.Id);
}
else
{
temp = PostService.LoadPageEntitiesNoTracking(page, size, out total, p => p.Status == Status.Pending && (p.Title.Contains(search) || p.Author.Contains(search) || p.Email.Contains(search) || p.Label.Contains(search)), p => p.Id);
}
var plist = temp.OrderByDescending(p => p.IsFixedTop).ThenByDescending(p => p.ModifyDate).Select(p => new
{
p.Id,
p.Author,
CategoryName = p.Category.Name,
p.Email,
p.IsFixedTop,
p.Label,
md = p.ModifyDate,
pd = p.PostDate,
p.Title,
ViewCount = p.TotalViewCount,
p.VoteDownCount,
p.VoteUpCount,
stat = p.Status
}).ToList();
var list = new List();
plist.ForEach(item =>
{
PostDataModel model = item.MapTo();
model.PostDate = item.pd.ToString("yyyy-MM-dd HH:mm");
model.ModifyDate = item.md.ToString("yyyy-MM-dd HH:mm");
model.Status = item.stat.GetDisplay();
list.Add(model);
});
var pageCount = Math.Ceiling(total * 1.0 / size).ToInt32();
return PageResult(list, pageCount, total);
}
///
/// 编辑
///
///
///
///
///
[HttpPost, Authority]
public ActionResult Edit(PostInputDto post, bool notify = true, bool reserve = true)
{
post.Content = CommonHelper.ReplaceImgSrc(Regex.Replace(post.Content.Trim(), @"
]*\s*src\s*=\s*['""]?(\S+\.\w{3,4})['""]?[^/>]*/>", "
")).Replace("/thumb150/", "/large/");
if (!CategoryService.Any(c => c.Id == post.CategoryId && c.Status == Status.Available))
{
return ResultData(null, message: "请选择一个分类");
}
if (string.IsNullOrEmpty(post.Label?.Trim()) || post.Label.Equals("null"))
{
post.Label = null;
}
else if (post.Label.Trim().Length > 50)
{
post.Label = post.Label.Replace(",", ",");
post.Label = post.Label.Trim().Substring(0, 50);
}
else
{
post.Label = post.Label.Replace(",", ",");
}
if (!post.IsWordDocument)
{
post.ResourceName = null;
}
if (string.IsNullOrEmpty(post.ProtectContent) || post.ProtectContent.Equals("null", StringComparison.InvariantCultureIgnoreCase))
{
post.ProtectContent = null;
}
Post p = PostService.GetById(post.Id);
if (reserve)
{
post.ModifyDate = DateTime.Now;
var history = p.Mapper();
history.Id = 0;
p.PostHistoryVersion.Add(history);
}
p.IP = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
Mapper.Map(post, p);
if (!string.IsNullOrEmpty(post.Seminars))
{
var tmp = post.Seminars.Split(',').Distinct();
p.Seminar.Clear();
tmp.ForEach(s =>
{
Seminar seminar = SeminarService.GetFirstEntity(e => e.Title.Equals(s));
p.Seminar.Add(new SeminarPost()
{
Post = p,
Seminar = seminar,
PostId = p.Id,
SeminarId = seminar.Id
});
});
}
bool b = PostService.UpdateEntitySaved(p);
if (b)
{
#if !DEBUG
if (notify && "false" == CommonHelper.SystemSettings["DisabledEmailBroadcast"])
{
var cast = BroadcastService.LoadEntities(c => c.Status == Status.Subscribed).ToList();
string link = Request.Scheme + "://" + Request.Host + "/" + p.Id;
cast.ForEach(c =>
{
var ts = DateTime.Now.GetTotalMilliseconds();
string content = System.IO.File.ReadAllText(Path.Combine(_hostingEnvironment.WebRootPath, "template", "broadcast.html"))
.Replace("{{link}}", link + "?email=" + c.Email)
.Replace("{{time}}", post.ModifyDate.ToString("yyyy-MM-dd HH:mm:ss"))
.Replace("{{title}}", post.Title)
.Replace("{{author}}", post.Author)
.Replace("{{content}}", post.Content.RemoveHtmlTag(150))
.Replace("{{cancel}}", Url.Action("Subscribe", "Subscribe", new
{
c.Email,
act = "cancel",
validate = c.ValidateCode,
timespan = ts,
hash = (c.Email + "cancel" + c.ValidateCode + ts).AESEncrypt(AppConfig.BaiduAK)
}, Request.Scheme));
BackgroundJob.Schedule(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Title"] + "博客有新文章发布了", content, c.Email), (p.ModifyDate - DateTime.Now));
});
}
#endif
return ResultData(p.Mapper(), message: "文章修改成功!");
}
return ResultData(null, false, "文章修改失败!");
}
///
/// 发布
///
///
///
///
///
[Authority, HttpPost]
public ActionResult Write(PostInputDto post, DateTime? timespan, bool schedule = false)
{
post.Content = CommonHelper.ReplaceImgSrc(Regex.Replace(post.Content.Trim(), @"
]*\s*src\s*=\s*['""]?(\S+\.\w{3,4})['""]?[^/>]*/>", "
")).Replace("/thumb150/", "/large/"); //提取img标签,提取src属性并重新创建个只包含src属性的img标签
if (!CategoryService.Any(c => c.Id == post.CategoryId && c.Status == Status.Available))
{
return ResultData(null, message: "请选择一个分类");
}
if (string.IsNullOrEmpty(post.Label?.Trim()) || post.Label.Equals("null"))
{
post.Label = null;
}
else if (post.Label.Trim().Length > 50)
{
post.Label = post.Label.Replace(",", ",");
post.Label = post.Label.Trim().Substring(0, 50);
}
else
{
post.Label = post.Label.Replace(",", ",");
}
if (!post.IsWordDocument)
{
post.ResourceName = null;
}
if (string.IsNullOrEmpty(post.ProtectContent) || post.ProtectContent.Equals("null", StringComparison.InvariantCultureIgnoreCase))
{
post.ProtectContent = null;
}
post.Status = Status.Pended;
post.PostDate = DateTime.Now;
post.ModifyDate = DateTime.Now;
Post p = post.Mapper();
p.IP = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
if (!string.IsNullOrEmpty(post.Seminars))
{
var tmp = post.Seminars.Split(',').Distinct();
tmp.ForEach(s =>
{
var id = s.ToInt32();
Seminar seminar = SeminarService.GetById(id);
p.Seminar.Add(new SeminarPost()
{
Post = p,
PostId = p.Id,
Seminar = seminar,
SeminarId = seminar.Id
});
});
}
p.PostAccessRecord.Add(new PostAccessRecord()
{
AccessTime = DateTime.Today,
ClickCount = 0
});
if (schedule)
{
if (timespan.HasValue && timespan.Value > DateTime.Now)
{
p.Status = Status.Schedule;
p.PostDate = timespan.Value;
p.ModifyDate = timespan.Value;
HangfireHelper.CreateJob(typeof(IHangfireBackJob), nameof(HangfireBackJob.PublishPost), args: p);
return ResultData(p.Mapper(), message: schedule ? $"文章于{timespan.Value:yyyy-MM-dd HH:mm:ss}将会自动发表!" : "文章发表成功!");
}
return ResultData(null, false, "如果要定时发布,请选择正确的一个将来时间点!");
}
bool b = PostService.AddEntitySaved(p) != null;
if (b)
{
if ("false" == CommonHelper.SystemSettings["DisabledEmailBroadcast"])
{
var cast = BroadcastService.LoadEntities(c => c.Status == Status.Subscribed).ToList();
string link = Request.Scheme + "://" + Request.Host + "/" + p.Id;
cast.ForEach(c =>
{
var ts = DateTime.Now.GetTotalMilliseconds();
string content = System.IO.File.ReadAllText(_hostingEnvironment.WebRootPath + "/template/broadcast.html").Replace("{{link}}", link + "?email=" + c.Email).Replace("{{time}}", post.ModifyDate.ToString("yyyy-MM-dd HH:mm:ss")).Replace("{{title}}", post.Title).Replace("{{author}}", post.Author).Replace("{{content}}", post.Content.RemoveHtmlTag(150)).Replace("{{cancel}}", Url.Action("Subscribe", "Subscribe", new
{
c.Email,
act = "cancel",
validate = c.ValidateCode,
timespan = ts,
hash = (c.Email + "cancel" + c.ValidateCode + ts).AESEncrypt(AppConfig.BaiduAK)
}, Request.Scheme));
BackgroundJob.Schedule(() => CommonHelper.SendMail(CommonHelper.SystemSettings["Title"] + "博客有新文章发布了", content, c.Email), (p.ModifyDate - DateTime.Now));
});
}
return ResultData(null, true, "文章发表成功!");
}
return ResultData(null, false, "文章发表失败!");
}
///
/// 添加专题
///
///
///
///
[Authority]
public ActionResult AddSeminar(int id, int sid)
{
var post = PostService.GetById(id);
Seminar seminar = SeminarService.GetById(sid);
post.Seminar.Add(new SeminarPost()
{
Post = post,
Seminar = seminar,
SeminarId = seminar.Id,
PostId = post.Id
});
bool b = PostService.UpdateEntitySaved(post);
return ResultData(null, b, b ? $"已将文章【{post.Title}】添加到专题【{seminar.Title}】" : "添加失败");
}
///
/// 移除专题
///
///
///
///
[Authority]
public ActionResult RemoveSeminar(int id, int sid)
{
var post = PostService.GetById(id);
Seminar seminar = SeminarService.GetById(sid);
post.Seminar.Remove(new SeminarPost()
{
Post = post,
Seminar = seminar,
SeminarId = seminar.Id,
PostId = post.Id
});
bool b = PostService.UpdateEntitySaved(post);
return ResultData(null, b, b ? $"已将文章【{post.Title}】从【{seminar.Title}】专题移除" : "添加失败");
}
///
/// 删除历史版本
///
///
///
[Authority]
public ActionResult DeleteHistory(int id)
{
bool b = PostHistoryVersionService.DeleteByIdSaved(id);
return ResultData(null, b, b ? "历史版本文章删除成功!" : "历史版本文章删除失败!");
}
///
/// 获取文章访问密码
///
///
[Authority, HttpPost]
public ActionResult ViewToken()
{
if (!RedisHelper.Exists("ArticleViewToken"))
{
RedisHelper.Set("ArticleViewToken", SnowFlake.GetInstance().GetUniqueShortId(6));
}
var token = RedisHelper.Get("ArticleViewToken");
return ResultData(token);
}
///
/// 还原版本
///
///
///
public ActionResult Revert(int id)
{
var history = PostHistoryVersionService.GetById(id);
if (history != null)
{
//var version = history.Post.Mapper();
//version.Id = 0;
//PostHistoryVersionService.AddEntity(version);
history.Post.Category = history.Category;
history.Post.CategoryId = history.CategoryId;
history.Post.Content = history.Content;
history.Post.Title = history.Title;
history.Post.Label = history.Label;
history.Post.Seminar.Clear();
foreach (var s in history.Seminar)
{
history.Post.Seminar.Add(new SeminarPost()
{
Post = history.Post,
PostId = history.PostId,
Seminar = s.Seminar,
SeminarId = s.SeminarId
});
}
history.Post.ModifyDate = history.ModifyDate;
bool b = PostHistoryVersionService.UpdateEntitySaved(history);
PostHistoryVersionService.DeleteByIdSaved(id);
return ResultData(null, b, b ? "回滚成功" : "回滚失败");
}
return ResultData(null, false, "版本不存在");
}
///
/// 文章分析
///
///
///
[HttpPost]
public ActionResult Analyse(int id)
{
var list = PostService.GetById(id).PostAccessRecord.OrderBy(r => r.AccessTime).GroupBy(r => r.AccessTime.Date).Select(r => new[]
{
r.Key.GetTotalMilliseconds(),
r.Sum(p => p.ClickCount)
}).ToList();
var high = list.OrderByDescending(n => n[1]).FirstOrDefault();
var average = list.Average(d => d[1]);
return ResultData(new
{
list,
aver = average,
high = high[1],
highDate = DateTime.Parse("1970-01-01").AddMilliseconds(high[0])
});
}
#endregion
}
}