public async Task Test_03_AddCommentIncludeBaseComment() { using(KoalaBlogDbContext dbContext = new KoalaBlogDbContext()) { BlogHandler blogHandler = new BlogHandler(dbContext); ContentHandler contentHandler = new ContentHandler(dbContext); CommentHandler commentHandler = new CommentHandler(dbContext); CommentXCommentHandler cxcHandler = new CommentXCommentHandler(dbContext); CommentXContentHandler ccHandler = new CommentXContentHandler(dbContext); Person rain = CreatePerson("TestRain", "TestRain", AllowablePersonForComment.All, true); Blog testBlog = await blogHandler.CreateBlogAsync(rain.ID, "TestCommentBlog", BlogInfoAccessInfo.MyselfOnly); //1. test normal. List<long> contentIds = new List<long>(); Content content = new Content() { ContentPath = "testBeCommentPath", ContentBinary = new byte[] { 1, 3, 5 }, Type = ContentType.Photo, MimeType = "jpg" }; contentHandler.Add(content); contentHandler.SaveChanges(); contentIds.Add(content.ID); Comment beComment = await commentHandler.AddCommentAsync(commentPerson.ID, testBlog.ID, "hey, i am be comment test.", photoContentIds: contentIds); Comment test_beComment = await commentHandler.GetByIdAsync(beComment.ID); Assert.IsNotNull(test_beComment); Assert.AreEqual(test_beComment.PersonID, commentPerson.ID); Assert.AreEqual(test_beComment.BlogID, testBlog.ID); Assert.AreEqual(test_beComment.Content, "hey, i am be comment test."); Assert.AreEqual(test_beComment.CommentXContents.Count, 1); Assert.AreEqual(test_beComment.CommentXContents.First().Content.ContentPath, "testBeCommentPath"); Assert.AreEqual(test_beComment.CommentXContents.First().Content.Type, ContentType.Photo); Assert.AreEqual(test_beComment.CommentXContents.First().Content.ContentBinary, new byte[] { 1, 3, 5 }); contentIds = new List<long>(); Content newCommentContent = new Content() { ContentPath = "testBeCommentPath", ContentBinary = new byte[] { 1, 3, 5 }, Type = ContentType.Photo, MimeType = "jpg" }; contentHandler.Add(newCommentContent); contentHandler.SaveChanges(); contentIds.Add(newCommentContent.ID); Comment newComment = await commentHandler.AddCommentAsync(commentPerson.ID, testBlog.ID, "hey, i am new comment test.", photoContentIds: contentIds, baseCommentId: test_beComment.ID); Comment test_newComment = await commentHandler.GetByIdAsync(newComment.ID); Assert.IsNotNull(test_newComment); Assert.AreEqual(test_newComment.PersonID, commentPerson.ID); Assert.AreEqual(test_newComment.BlogID, testBlog.ID); Assert.AreEqual(test_newComment.Content, "hey, i am new comment test."); Assert.AreEqual(test_newComment.CommentXContents.Count, 1); Assert.AreEqual(test_newComment.NewCommentXComments.Count, 1); Assert.AreEqual(test_newComment.CommentXContents.First().Content.ContentPath, "testBeCommentPath"); Assert.AreEqual(test_newComment.CommentXContents.First().Content.Type, ContentType.Photo); Assert.AreEqual(test_newComment.CommentXContents.First().Content.ContentBinary, new byte[] { 1, 3, 5 }); Assert.AreEqual(test_newComment.NewCommentXComments.First().BaseComment.ID, test_beComment.ID); Assert.AreEqual(test_newComment.NewCommentXComments.First().NewComment.ID, test_newComment.ID); Assert.AreEqual(test_newComment.NewCommentXComments.First().BaseComment.Content, "hey, i am be comment test."); Assert.AreEqual(test_newComment.NewCommentXComments.First().NewComment.Content, "hey, i am new comment test."); //2. delete a comment and test it. bool isChecked = false; try { long tmpCommentId = test_beComment.ID; //delete comment. //2.1 first, delete all navigation for comment. for (int i = 0; i < test_beComment.BaseCommentXComments.Count; i++) { cxcHandler.MarkAsDeleted(test_beComment.BaseCommentXComments.ElementAt(i)); } await cxcHandler.SaveChangesAsync(); for (int i = 0; i < test_beComment.CommentXContents.Count; i++) { ccHandler.MarkAsDeleted(test_beComment.CommentXContents.ElementAt(i)); } await ccHandler.SaveChangesAsync(); //2.2 then, delete comment. commentHandler.MarkAsDeleted(test_beComment); await commentHandler.SaveChangesAsync(); Comment test_notExistComment = await commentHandler.AddCommentAsync(commentPerson.ID, testBlog.ID, "hey, i am new comment test.", baseCommentId: tmpCommentId); } catch (Exception ex) { isChecked = true; Assert.AreEqual(ex.GetType(), typeof(DisplayableException)); Assert.AreEqual(ex.Message, "此评论不存在或者已经被删除"); } Assert.IsTrue(isChecked); } }
/// <summary> /// 获取Blog的评论 /// </summary> /// <param name="blogId">BlogID</param> /// <param name="pageIndex"></param> /// <param name="pageSize"></param> /// <returns></returns> public async Task<Tuple<int, List<CommentDTO>>> GetCommentsAsync(long blogId, int pageIndex, int pageSize) { using(KoalaBlogDbContext dbContext = new KoalaBlogDbContext()) { int totalCommentCount = 0; List<CommentDTO> commentDtoList = null; PersonHandler perHandler = new PersonHandler(dbContext); AvatarHandler avatarHandler = new AvatarHandler(dbContext); CommentHandler commentHandler = new CommentHandler(dbContext); CommentXContentHandler cxContentHandler = new CommentXContentHandler(dbContext); CommentXCommentHandler cxCommentHandler = new CommentXCommentHandler(dbContext); //1. 获取Blog评论列表。 var comments = await commentHandler.GetCommentsAsync(blogId, pageIndex, pageSize); if (comments.Count > 0) { commentDtoList = new List<CommentDTO>(); foreach (var comment in comments) { CommentDTO commentDto = comment.ToDTO(); //2. 判断Person对象是否为空,如果为空则获取。 if (commentDto.Person == null) { var personEntity = await perHandler.GetByIdAsync(comment.PersonID); if (personEntity != null) { commentDto.Person = personEntity.ToDTO(); //2.1 判断头像Url是否已经获取。 if (string.IsNullOrEmpty(commentDto.Person.AvatarUrl)) { commentDto.Person.AvatarUrl = await avatarHandler.GetActiveAvatarUrlByPersonId(comment.PersonID); } } } else { //2.2 如果Person对象不为空,判断头像Url是否已经获取。 if (string.IsNullOrEmpty(commentDto.Person.AvatarUrl)) { commentDto.Person.AvatarUrl = await avatarHandler.GetActiveAvatarUrlByPersonId(comment.PersonID); } } //3. 判断Contents集合是否为空,如果为空则获取。 if (commentDto.Contents == null) { List<Content> contentList = await cxContentHandler.GetContentsAsync(comment.ID); if (contentList != null && contentList.Count > 0) { commentDto.Contents = new List<ContentDTO>(); foreach (var content in contentList) { ContentDTO contentDto = content.ToDTO(); commentDto.Contents.Add(contentDto); } } } //4. 判断此评论是否评论了其他的评论。 if (commentDto.BaseComment == null) { Comment baseComment = await cxCommentHandler.GetBaseCommentByCommentIdAsync(comment.ID); if (baseComment != null) { commentDto.BaseComment = baseComment.ToDTO(); //4.1 判断Person对象是否为空,如果为空则获取,这里暂时不需要获取Avatar。 if (commentDto.BaseComment.Person == null) { var personEntity = await perHandler.GetByIdAsync(baseComment.PersonID); if (personEntity != null) { commentDto.BaseComment.Person = personEntity.ToDTO(); } } } } //5. 获取评论点赞数量Task。 Task<int> likeCountTask = GetCommentLikeCountAsync(comment.ID); //6. 判断用户是否点赞了此评论Task。 Task<bool> isLikeTask = IsLikeAsync(CurrentThreadIdentityObject.PersonID, comment.ID); commentDto.IsLike = await isLikeTask; commentDto.LikeCount = await likeCountTask; commentDtoList.Add(commentDto); } //7. 获取Blog的总评论数量。 totalCommentCount = await GetCommentCountAsync(blogId); } return new Tuple<int, List<CommentDTO>>(totalCommentCount, commentDtoList); } }
/// <summary> /// 添加一条评论 /// </summary> /// <param name="personId">评论者ID</param> /// <param name="blogId">评论的BlogID</param> /// <param name="content">评论内容</param> /// <param name="photoContentIds">评论的附件ID(仅限图片)</param> /// <param name="baseCommentId">被评论的CommentID</param> /// <returns></returns> public async Task<Comment> AddCommentAsync(long personId, long blogId, string content, List<long> photoContentIds = null, long? baseCommentId = null) { BlogHandler blogHandler = new BlogHandler(_dbContext); GroupHandler groupHandler = new GroupHandler(_dbContext); PersonHandler perHandler = new PersonHandler(_dbContext); //1. 检查要评论的Blog是否存在。 Blog beCommentBlog = await blogHandler.GetByIdAsync(blogId); //2. 如果为空或者被逻辑删除,则Exception。 if (beCommentBlog == null || beCommentBlog.IsDeleted) { throw new DisplayableException("要评论的Blog不存在或者已经被删除"); } //2.1 自己评论自己的Blog永远可以,所以只需要判断不同的PersonID。 if(beCommentBlog.PersonID != personId) { //3. 检查当前用户是否被该评论Blog的用户加入了黑名单,如果是则不能进行评论。 Group beCommentBlogPersonBlackList = await groupHandler.Include(x => x.GroupMembers).SingleOrDefaultAsync(x => x.PersonID == beCommentBlog.PersonID && x.Type == GroupType.BlackList); if (beCommentBlogPersonBlackList != null && beCommentBlogPersonBlackList.GroupMembers.Count > 0) { bool isBlocked = beCommentBlogPersonBlackList.GroupMembers.Select(x => x.PersonID).Contains(personId); if (isBlocked) { throw new DisplayableException("由于用户设置,你无法回复评论。"); } } //4. 检查评论Blog的用户消息设置,是否允许评论。 Person beCommentBlogPerson = await perHandler.GetByIdAsync(beCommentBlog.PersonID); if (beCommentBlogPerson != null) { //4.1 如果评论只允许关注的人评论,则判断Blog的用户的是否关注了当前用户。 if (beCommentBlogPerson.AllowablePersonForComment == AllowablePersonForComment.FollowerOnly) { //4.2 判断关注的人集合是否已经加载。 if (!_dbContext.Entry(beCommentBlogPerson).Collection(x => x.MyFollowingPersons).IsLoaded) { _dbContext.Entry(beCommentBlogPerson).Collection(x => x.MyFollowingPersons).Load(); } bool isFollow = beCommentBlogPerson.MyFollowingPersons.Select(x => x.FollowingID).Contains(personId); if (!isFollow) { throw new DisplayableException("由于用户设置,你无法回复评论。"); } } //4.3 如果评论只允许粉丝评论,则判断当前用户是否关注了该Blog用户。 else if (beCommentBlogPerson.AllowablePersonForComment == AllowablePersonForComment.FansOnly) { //4.4 判断粉丝集合是否已经加载。 if (!_dbContext.Entry(beCommentBlogPerson).Collection(x => x.MyFans).IsLoaded) { _dbContext.Entry(beCommentBlogPerson).Collection(x => x.MyFans).Load(); } bool isFans = beCommentBlogPerson.MyFans.Select(x => x.FollowerID).Contains(personId); if (!isFans) { throw new DisplayableException("由于用户设置,你无法回复评论。"); } } } //5. 检查评论Blog的用户消息设置,是否允许评论附带图片。 if(photoContentIds != null && photoContentIds.Count > 0) { if(!beCommentBlogPerson.AllowCommentAttachContent) { throw new DisplayableException("由于用户设置,你回复评论无法添加图片。"); } } } using(var dbTransaction = _dbContext.Database.BeginTransaction()) { try { //6. 建立Comment对象并保存。 Comment comment = new Comment() { PersonID = personId, BlogID = blogId, Content = content }; this.Add(comment); await SaveChangesAsync(); //7. 判断是否有图片,有则建立与Comment的关联。 if (photoContentIds != null && photoContentIds.Count > 0) { if(photoContentIds.Count > 6) { throw new DisplayableException("评论最多附件6张图片"); } ContentHandler contentHandler = new ContentHandler(_dbContext); //7.1 判断附件是否为图片。 List<Content> photoContents = await contentHandler.Fetch(x => photoContentIds.Contains(x.ID)).ToListAsync(); if(!photoContents.Any(x => x.Type == ContentType.Photo)) { throw new DisplayableException("评论只能附件图片"); } //7.2 建立Comment与Content的关联。 CommentXContentHandler cxcHandler = new CommentXContentHandler(_dbContext); foreach (var photoContentId in photoContentIds) { CommentXContent cxc = new CommentXContent() { CommentID = comment.ID, ContentID = photoContentId }; cxcHandler.Add(cxc); } await SaveChangesAsync(); } //8. 判断当前评论是否评论Blog里的其他评论,如果是则建立关联。 if(baseCommentId != null) { //8.1 判断被评论ID是否存在。 Comment baseComment = await GetByIdAsync(baseCommentId); if(baseComment == null) { throw new DisplayableException("此评论不存在或者已经被删除"); } //8.2 判断被评论的BlogID是否与当前评论的BlogID一致。 if(baseComment.BlogID != blogId) { throw new DisplayableException("此评论的BlogID与被评论的BlogID不一致"); } //8.3 建立关联。 CommentXCommentHandler cxcHandler = new CommentXCommentHandler(_dbContext); CommentXComment cxc = new CommentXComment() { BaseCommentID = (long)baseCommentId, NewCommentID = comment.ID }; cxcHandler.Add(cxc); await SaveChangesAsync(); } dbTransaction.Commit(); return comment; } catch (Exception) { dbTransaction.Rollback(); throw; } } }