/// <summary> /// 创建 <see cref="ArticlePage"/> /// </summary> /// <param name="authorIdCode">作者识别码</param> /// <param name="sidForAuthor">文章在作者名下的序号</param> /// <param name="currentUserId">当前登录用户 ID</param> /// <param name="isOperator">当前登录用户是否为运维职员</param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="cachedData"><see cref="CachedDataProvider"/></param> /// <param name="userManager"><see cref="KeylolUserManager"/></param> /// <returns><see cref="ArticlePage"/></returns> public static async Task <ArticlePage> CreateAsync(string authorIdCode, int sidForAuthor, string currentUserId, bool isOperator, KeylolDbContext dbContext, CachedDataProvider cachedData, KeylolUserManager userManager) { var articlePage = new ArticlePage(); var article = await dbContext.Articles .Include(a => a.Author) .Include(a => a.TargetPoint) .Where(a => a.Author.IdCode == authorIdCode && a.SidForAuthor == sidForAuthor) .SingleOrDefaultAsync(); if (article == null) { return(articlePage); } articlePage.Archived = article.Archived != ArchivedState.None; if (articlePage.Archived.Value && currentUserId != article.AuthorId && !isOperator) { return(articlePage); } articlePage.PointBasicInfo = await PointBasicInfo.CreateAsync(currentUserId, article.TargetPoint, dbContext, cachedData); articlePage.AuthorBasicInfo = new UserBasicInfo { Id = article.Author.Id, IdCode = article.Author.IdCode, AvatarImage = article.Author.AvatarImage, UserName = article.Author.UserName, FriendCount = await cachedData.Subscriptions.GetFriendCountAsync(article.AuthorId), SubscribedUserCount = await cachedData.Subscriptions .GetSubscribedUserCountAsync(article.AuthorId), SubscriberCount = await cachedData.Subscriptions .GetSubscriberCountAsync(article.AuthorId, SubscriptionTargetType.User), IsFriend = string.IsNullOrWhiteSpace(currentUserId) ? (bool?)null : await cachedData.Users.IsFriendAsync(currentUserId, article.AuthorId), Subscribed = string.IsNullOrWhiteSpace(currentUserId) ? (bool?)null : await cachedData.Subscriptions.IsSubscribedAsync(currentUserId, article.AuthorId, SubscriptionTargetType.User), SteamId = await userManager.GetSteamIdAsync(article.AuthorId) }; if (!string.IsNullOrWhiteSpace(articlePage.AuthorBasicInfo.SteamId)) { articlePage.AuthorBasicInfo.SteamProfileName = article.Author.SteamProfileName; } articlePage.AuthorPlayedTime = article.TargetPoint.SteamAppId == null ? null : (await dbContext.UserSteamGameRecords .Where(r => r.UserId == article.AuthorId && r.SteamAppId == article.TargetPoint.SteamAppId) .SingleOrDefaultAsync())?.TotalPlayedTime; articlePage.Id = article.Id; articlePage.Title = article.Title; articlePage.Subtitle = article.Subtitle; var attachedPointIds = Helpers.SafeDeserialize <List <string> >(article.AttachedPoints) ?? new List <string>(); articlePage.AttachedPoints = (from id in attachedPointIds join point in await(from point in dbContext.Points where attachedPointIds.Contains(point.Id) select new { point.Type, point.Id, point.IdCode, point.AvatarImage, point.ChineseName, point.EnglishName }).ToListAsync() on id equals point.Id select new PointBasicInfo { Type = point.Type, Id = point.Id, IdCode = point.IdCode, AvatarImage = point.AvatarImage, ChineseName = point.ChineseName, EnglishName = point.EnglishName }).ToList(); articlePage.PublishTime = article.PublishTime; articlePage.Rejected = article.Rejected; articlePage.Spotlighted = article.Spotlighted; articlePage.Warned = article.Warned; articlePage.Content = article.Content; articlePage.ReproductionRequirement = Helpers.SafeDeserialize <ReproductionRequirement>(article.ReproductionRequirement); articlePage.LikeCount = await cachedData.Likes.GetTargetLikeCountAsync(article.Id, LikeTargetType.Article); articlePage.Liked = string.IsNullOrWhiteSpace(currentUserId) ? (bool?)null : await cachedData.Likes.IsLikedAsync(currentUserId, article.Id, LikeTargetType.Article); articlePage.Rating = article.Rating; articlePage.CoverImage = article.CoverImage; articlePage.Pros = Helpers.SafeDeserialize <List <string> >(article.Pros); articlePage.Cons = Helpers.SafeDeserialize <List <string> >(article.Cons); articlePage.RecommendedArticles = await RecommendedArticleList.CreateAsync(article.Id, article.AuthorId, article.TargetPointId, dbContext); var comments = await ArticleCommentList.CreateAsync(article, 1, currentUserId, isOperator, true, dbContext, cachedData); articlePage.CommentCount = comments.Item2; articlePage.LatestCommentTime = comments.Item3; articlePage.CommentPageCount = comments.Item4; articlePage.Comments = comments.Item1; return(articlePage); }
/// <summary> /// 创建 <see cref="ArticleCommentList"/> /// </summary> /// <param name="article">文章对象</param> /// <param name="page">分页页码</param> /// <param name="currentUserId">当前登录用户 ID</param> /// <param name="isOperator">当前登录用户是否为运维职员</param> /// <param name="returnMeta">是否返回元数据(总页数、总评论数、最新评论时间)</param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="cachedData"><see cref="CachedDataProvider"/></param> /// <returns>Item1 表示 <see cref="ArticleCommentList"/>, Item2 表示总评论数,Item3 表示最新评论时间,Item4 表示总页数</returns> public static async Task <Tuple <ArticleCommentList, int, DateTime?, int> > CreateAsync(Models.Article article, int page, string currentUserId, bool isOperator, bool returnMeta, KeylolDbContext dbContext, CachedDataProvider cachedData) { if (article.Archived != ArchivedState.None && currentUserId != article.AuthorId && !isOperator) { return(new Tuple <ArticleCommentList, int, DateTime?, int>(new ArticleCommentList(0), 0, null, 0)); } var queryResult = await(from comment in dbContext.ArticleComments where comment.ArticleId == article.Id orderby comment.Sid select new { Author = comment.Commentator, comment.Id, comment.PublishTime, comment.SidForArticle, comment.Content, comment.ReplyToComment, ReplyToCommentAuthor = comment.ReplyToComment.Commentator, comment.Archived, comment.Warned }).TakePage(page, RecordsPerPage).ToListAsync(); var result = new ArticleCommentList(queryResult.Count); foreach (var c in queryResult) { var articleComment = new ArticleComment { Id = c.Id, SidForArticle = c.SidForArticle, Archived = c.Archived != ArchivedState.None }; // ReSharper disable once PossibleInvalidOperationException if (!articleComment.Archived.Value || currentUserId == c.Author.Id || isOperator) { articleComment.AuthorIdCode = c.Author.IdCode; articleComment.AuthorAvatarImage = c.Author.AvatarImage; articleComment.AuthorUserName = c.Author.UserName; articleComment.AuthorPlayedTime = article.TargetPoint.SteamAppId == null ? null : (await dbContext.UserSteamGameRecords .Where(r => r.UserId == c.Author.Id && r.SteamAppId == article.TargetPoint.SteamAppId) .SingleOrDefaultAsync())?.TotalPlayedTime; articleComment.LikeCount = await cachedData.Likes.GetTargetLikeCountAsync(c.Id, LikeTargetType.ArticleComment); articleComment.Liked = string.IsNullOrWhiteSpace(currentUserId) ? (bool?)null : await cachedData.Likes.IsLikedAsync(currentUserId, c.Id, LikeTargetType.ArticleComment); articleComment.PublishTime = c.PublishTime; articleComment.Content = c.Content; if (c.ReplyToComment != null) { articleComment.ReplyToComment = new ArticleComment { SidForArticle = c.ReplyToComment.SidForArticle, AuthorAvatarImage = c.ReplyToCommentAuthor.AvatarImage, AuthorUserName = c.ReplyToCommentAuthor.UserName, AuthorIdCode = c.ReplyToCommentAuthor.IdCode, Content = c.ReplyToComment.UnstyledContent.Length > 150 ? c.ReplyToComment.UnstyledContent.Substring(0, 150) : c.ReplyToComment.UnstyledContent }; } articleComment.Warned = c.Warned; } result.Add(articleComment); } var latestCommentTime = returnMeta ? await(from comment in dbContext.ArticleComments where comment.ArticleId == article.Id orderby comment.Sid descending select comment.PublishTime).FirstOrDefaultAsync() : default(DateTime); var count = await cachedData.ArticleComments.GetArticleCommentCountAsync(article.Id); return(new Tuple <ArticleCommentList, int, DateTime?, int>(result, count, latestCommentTime == default(DateTime) ? (DateTime?)null : latestCommentTime, count > 0 ? (int)Math.Ceiling(count / (double)RecordsPerPage) : 1)); }