private int UpdateChildrenCount(CommentTreeContext context, CommentTree commentTree, List <Guid> comments) { var childrenCount = comments.Count; foreach (var comment in comments) { if (context.CommentsChildrenCount.ContainsKey(comment)) { continue; } if (!commentTree.Tree.ContainsKey(comment)) { context.CommentsChildrenCount[comment] = 0; continue; } var count = UpdateChildrenCount(context, commentTree, commentTree.Tree[comment]); context.CommentsChildrenCount[comment] = count; childrenCount += count; } return(childrenCount); }
private CommentTree GetCommentTree(List <RedditComment> comments, RedditComment comment, bool parity) { List <RedditComment> children = comments.Where(child => child.parentID.ToString() == comment.id.ToString()).ToList(); if (children.Count == 0) { comment.parity = parity; return(new CommentTree() { children = null, comment = comment }); } else { RedditComment whatcomment = comment; comment.parity = parity; CommentTree rt = new CommentTree() { children = new List <CommentTree>(), comment = whatcomment }; List <CommentTree> what = new List <CommentTree>(); foreach (var item in children) { what.Add(GetCommentTree(comments, item, !parity)); } rt.children = what; return(rt); } }
public CommentTree GetCommentTree(Guid postId) { //todo: this method is very db intensive. however, it should be easy to improve performance once // a caching strategy is implemented. var comments = _commentService.GetAllCommentsForPost(postId); var tree = new CommentTree { PostId = postId, CommentIds = comments.Select(x => x.Id).ToList(), Parents = comments.ToDictionary(x => x.Id, x => x.ParentId), Tree = new Dictionary <Guid, List <Guid> >(), Depth = comments.ToDictionary(x => x.Id, x => 0) }; // loop through comments to figure out if we have children comments foreach (var comment in comments) { List <Guid> children; var parentId = comment.ParentId ?? Guid.Empty; if (tree.Tree.ContainsKey(parentId)) { children = tree.Tree[parentId]; } else { children = new List <Guid>(); tree.Tree[parentId] = children; } children.Add(comment.Id); } // loop through commetns to figure out depth if there are children comments foreach (var comment in comments) { if (!comment.ParentId.HasValue) { tree.Depth[comment.Id] = 0; continue; } var parentId = comment.ParentId; var depth = 0; while (parentId.HasValue) { depth++; parentId = tree.Parents[parentId.Value]; } tree.Depth[comment.Id] = depth; } return(tree); }
private static string GenerateCommentHtml(CommentTree tree) { var sb = new StringBuilder(); for (int i = tree.branches.Count - 1; i >= 0; i--) { sb.Append(GenerateCommentHtml(tree.branches[i].comment, GenerateCommentHtml(tree.branches[i]))); } return(sb.ToString()); }
public CommentTree GetCommentTree(Guid postId) { // TODO: this method is very db intensive. however, it should be easy to improve the performance once a caching strategy is implemented. var comments = _commentService.GetAllCommentsForPost(postId); var tree = new CommentTree { PostId = postId, CommentIds = comments.Select(x => x.Id).ToList(), Parents = comments.ToDictionary(x => x.Id, x => x.ParentId), Tree = new Dictionary<Guid, List<Guid>>(), Depth = comments.ToDictionary(x => x.Id, x => 0) }; foreach (var comment in comments) { List<Guid> children; var parentId = comment.ParentId ?? Guid.Empty; if (tree.Tree.ContainsKey(parentId)) children = tree.Tree[parentId]; else { children = new List<Guid>(); tree.Tree[parentId] = children; } children.Add(comment.Id); } foreach (var comment in comments) { if (!comment.ParentId.HasValue) { tree.Depth[comment.Id] = 0; continue; } var parentId = comment.ParentId; var depth = 0; while (parentId.HasValue) { depth++; parentId = tree.Parents[parentId.Value]; } tree.Depth[comment.Id] = depth; } return tree; }
private List <HouseShow> GetApprovedShows() { var list = _dataAccessService.ExecuteProcedureAsync <HouseShow>("GetApprovedHouseShows").Result.ToList(); foreach (var concert in list) { var concertId = concert.EventConcertId; var allComments = GetAllComments(concertId); var tree = new CommentTree(allComments); concert.Comments = tree.GetEventComments(); } return(list); }
public async Task <IActionResult> Comments(string id) { RedditPost post = await _context.Posts.FindAsync(id); post.created_string = SecondsToAgoString((Int64)post.created_utc); List <RedditComment> RList = _context.Comments .Where(a => a.postID == id) .ToList(); RList.Reverse(); string current_id = post.id; CommentTree commentTree = new CommentTree(); commentTree.children = new List <CommentTree>(); commentTree.comment = null; List <RedditComment> TopLevelComments = RList.Where(a => a.parentID.ToString() == current_id).ToList(); foreach (var TopLevelComment in TopLevelComments) { CommentTree child_comment_tree = GetCommentTree(RList, TopLevelComment, true); commentTree.children.Add(child_comment_tree); } foreach (var item in RList) { item.createdString = SecondsToAgoString(item.unixTimestamp); } string subreddit = post.subreddit; CommentsPage commentsPage = new CommentsPage() { post = post, commentTree = commentTree }; return(View(commentsPage)); }
public IEnumerable <ICommentTree> CreateCommentTree(IEnumerable <GitComment> gitComments, char separator = '/') { Dictionary <long, GitComment> searchableGitComments = new Dictionary <long, GitComment>(); foreach (var comment in gitComments) { searchableGitComments.Add(comment.Id, comment); } Dictionary <int, List <ObjectTree> > result = new Dictionary <int, List <ObjectTree> >(); var maxLevel = -1; foreach (var comment in gitComments) { var level = 0; List <long> ids = new List <long>(); StringBuilder path = new StringBuilder(); ids.Add(comment.Id); var tmpComment = comment; while (tmpComment.Parent != null) { ids.Add(tmpComment.Parent.Id); level++; tmpComment = searchableGitComments[tmpComment.Parent.Id]; } if (!result.ContainsKey(level)) { result[level] = new List <ObjectTree>(); if (level > maxLevel) { maxLevel = level; } } for (var pathIndex = ids.Count - 1; pathIndex > -1; pathIndex -= 1) { path.Append(ids[pathIndex]); if (pathIndex > 0) { path.Append(separator); } } result[level].Add(new ObjectTree(path.ToString(), new GitComment() { Content = comment.Content, CreatedOn = comment.CreatedOn, Id = comment.Id, Parent = comment.Parent, User = comment.User, UpdatedOn = comment.UpdatedOn, Inline = comment.Inline, IsDeleted = comment.IsDeleted, Version = comment.Version })); } ICommentTree entryComment = new CommentTree(null); for (var i = 0; i <= maxLevel; i++) { List <ObjectTree> preparedComments = result[i]; foreach (var objectTree in preparedComments) { ICommentTree currentComment = entryComment; var pathChunks = objectTree.Path.Split(separator); foreach (var pathChunk in pathChunks) { var tmp = currentComment.Comments.Where(x => x.Comment.Id.Equals(long.Parse(pathChunk))); if (tmp.Any()) { currentComment = tmp.Single(); } else { ICommentTree newItem = new CommentTree(objectTree.GitComment); currentComment.Comments.Add(newItem); currentComment = newItem; } } } } return(entryComment.Comments); }
public List <ICommentNode> Build(CommentTree tree, CommentTreeContext treeContext, User currentUser) { var wrapped = _commentWrapper.Wrap(treeContext.Comments, currentUser).ToDictionary(x => x.Comment.Id, x => new CommentNode(x)); var final = new List <ICommentNode>(); var walked = new List <Guid>(); // lets mark any comments as collapsed if needed foreach (var comment in wrapped.Values) { // todo: make this configurable per-user int minimumScore = 0; if ((comment.Comment.Author != null && currentUser != null) && currentUser.Id == comment.Comment.Author.Id) { // the current user is the author, don't collapse! comment.Collapsed = false; } else if (comment.Comment.Score < minimumScore) { // to many down votes to show to the user comment.Collapsed = true; } else { // the current user is not the author, and we have enough upvotes to display, // don't collapse comment.Collapsed = false; } } foreach (var comment in wrapped.Values) { comment.NumberOfChildren = treeContext.CommentsChildrenCount[comment.Comment.Comment.Id]; CommentNode parent = null; if (comment.Comment.Comment.ParentId.HasValue) { parent = wrapped.ContainsKey(comment.Comment.Comment.ParentId.Value) ? wrapped[comment.Comment.Comment.ParentId.Value] : null; } if (comment.Comment.Comment.ParentId.HasValue && treeContext.Comments.Contains(comment.Comment.Comment.ParentId.Value)) { // parent comment is visible comment.IsParentVisible = true; } if (parent != null && comment.Comment.CurrentUserIsAuthor) { // this comment is the current user, so lets walk the parents // and uncollapse any comments which may be collapsed var ancestor = parent; while (ancestor != null && !walked.Contains(ancestor.Comment.Comment.Id)) { ancestor.Collapsed = false; walked.Add(ancestor.Comment.Comment.Id); ancestor = (ancestor.Comment.Comment.ParentId.HasValue && wrapped.ContainsKey(comment.Comment.Comment.ParentId.Value)) ? wrapped[comment.Comment.Comment.ParentId.Value] : null; } } if (treeContext.MoreRecursion.Contains(comment.Comment.Comment.Id)) { comment.Children.Add(new MoreRecursionNode(comment.Comment)); } if (parent != null) { comment.Parent = comment.Comment; parent.Children.Add(comment); } else { if (comment.Comment.Comment.ParentId.HasValue) { // we don't have a parent here, but this comment does have a parent // we need to get it comment.Parent = _commentWrapper.Wrap(comment.Comment.Comment.ParentId.Value); } final.Add(comment); } } foreach (var visibleId in wrapped.Keys) { // this item is already scheduled to have a new link to see all the children if (treeContext.MoreRecursion.Contains(visibleId)) { continue; } var children = tree.Tree.ContainsKey(visibleId) ? tree.Tree[visibleId] : new List <Guid>(); var missingChildren = children.Where(x => !treeContext.Comments.Contains(x)).ToList(); if (missingChildren.Count > 0) { var visibleChildren = children.Where(x => treeContext.Comments.Contains(x)).ToList(); var visibleCount = visibleChildren.Sum(x => (treeContext.CommentsChildrenCount[x]) + 1); var missingCount = treeContext.CommentsChildrenCount[visibleId] - visibleCount; var missingDepth = (tree.Depth.ContainsKey(visibleId) ? tree.Depth[visibleId] : 0) + 1 - treeContext.OffsetDepth; var moreChildren = new MoreChildren(); moreChildren.ChildComments.AddRange(missingChildren); moreChildren.MissingCount = missingCount; moreChildren.PostId = tree.PostId; moreChildren.Sort = treeContext.Sort; moreChildren.Depth = missingDepth; wrapped[visibleId].Children.Add(moreChildren); } } if (treeContext.TopLevelCandidates.Count > 0) { var moreChildren = new MoreChildren(); moreChildren.ChildComments.AddRange(treeContext.TopLevelCandidates); moreChildren.MissingCount = moreChildren.ChildComments.Sum(x => (treeContext.CommentsChildrenCount.ContainsKey(x) ? treeContext.CommentsChildrenCount[x] : 0) + 1); moreChildren.PostId = tree.PostId; moreChildren.Sort = treeContext.Sort; moreChildren.Depth = 0; final.Add(moreChildren); } return(final); }
#pragma warning restore 0649 private static void GetArticle(HttpListenerContext client, int categoryIndex) { var req = client.Request; var url = req.Url.Segments; if (url.Length < 3) { client.Error(HttpStatusCode.BadRequest); return; } if (url[url.Length - 1].Contains(".")) { client.GetFile(); return; } if (!articles[categoryIndex].ContainsKey(url[2])) { client.Error(HttpStatusCode.NotFound); return; } var article = articles[categoryIndex][url[2]]; var path = ChickenSoup.RootFolder + article.Path; if (File.Exists(path)) { var content = File.ReadAllText(path); var comments = article.GetComments(); var tree = new CommentTree(); foreach (var comment in comments) { if (!tree.Add(comment)) { throw new FormatException($"Comment file of {article.Name} has an invalid comment: {comment}"); } } var response = ArticleTemplate.Replace("{title}", article.Title) .Replace("{time}", article.Date.ToString()) .Replace("{time(O)}", article.Date.ToString("O")); Action <Article, string, string> replaceLinks = (otherArticle, replace, conditional) => { if (otherArticle != null) { response = response.Replace(replace, otherArticle.Url); response.Replace(replace, ""); response.Replace(conditional, ""); } else { var s = response.IndexOf(conditional, StringComparison.InvariantCulture); if (s < 0) { return; } var e = response.IndexOf(")}", s + conditional.Length, StringComparison.InvariantCulture) + 2; response = response.Remove(s, e - s); } }; replaceLinks(article.Next, "{next}", "{next??("); replaceLinks(article.Previous, "{previous}", "{previous??("); response = response.Replace("{content}", File.ReadAllText(path)) .Replace("{comments}", GenerateCommentHtml(tree)); client.WriteAndClose(response, "html", HttpStatusCode.OK); } else { client.Error(HttpStatusCode.NotFound); } }
public CommentTreeContext Build(CommentTree commentTree, Dictionary <Guid, double> sorter, List <Guid> children = null, Guid?comment = null, int?limit = null, int?maxDepth = null, int context = 0, bool continueThread = true, bool loadMore = true) { if (children != null && comment != null) { throw new Exception("You cannot build a tree for both a single comment, and multiple comments."); } var result = new CommentTreeContext(); result.MaxDepth = maxDepth; if (children != null && children.Count == 0) { return(result); } if (commentTree.CommentIds.Count == 0) { return(result); } if (sorter == null) { sorter = new Dictionary <Guid, double>(); } var candidates = new PriorityQueue <CommentQueue>(); if (children != null) { UpdateCandidates(candidates, sorter, children.Where(x => commentTree.CommentIds.Contains(x))); result.DontCollapse.AddRange(candidates.Select(x => x.CommentId)); } else if (comment.HasValue) { var currentComment = (Guid?)comment; var path = new List <Guid>(); if (!commentTree.CommentIds.Contains(comment.Value)) { throw new CommentNotFoundException(); } while (currentComment.HasValue && path.Count <= context) { path.Add(currentComment.Value); currentComment = commentTree.Parents[currentComment.Value]; } result.DontCollapse.AddRange(path); foreach (var commentId in path) { var parent = commentTree.Parents[commentId]; commentTree.Tree[parent ?? Guid.Empty] = new List <Guid> { commentId }; } UpdateCandidates(candidates, sorter, new List <Guid> { path[path.Count - 1] }); result.OffsetDepth = commentTree.Depth[path[path.Count - 1]]; } else { var topLevelComments = commentTree.Tree.ContainsKey(Guid.Empty) ? commentTree.Tree[Guid.Empty] : new List <Guid>(); UpdateCandidates(candidates, sorter, topLevelComments); } var items = new List <Guid>(); while ((!limit.HasValue || items.Count < limit.Value) && candidates.Count > 0) { var candidate = candidates.Dequeue(); var commentDepth = commentTree.Depth[candidate.CommentId] - result.OffsetDepth; if (!maxDepth.HasValue || commentDepth < maxDepth.Value) { items.Add(candidate.CommentId); if (commentTree.Tree.ContainsKey(candidate.CommentId)) { UpdateCandidates(candidates, sorter, commentTree.Tree[candidate.CommentId]); } } else if (continueThread && commentTree.Parents[candidate.CommentId] != null) { var parentId = commentTree.Parents[candidate.CommentId].Value; if (!result.MoreRecursion.Contains(parentId)) { result.MoreRecursion.Add(parentId); } } } result.Comments.AddRange(items); result.TopLevelComments.AddRange(result.Comments.Where(x => commentTree.Depth[x] == 0)); result.TopLevelCandidates = candidates.Where(x => ((commentTree.Depth.ContainsKey(x.CommentId) ? commentTree.Depth[x.CommentId] : 0) == 0)).Select(x => x.CommentId).ToList(); UpdateChildrenCount(result, commentTree, items.Union(result.TopLevelCandidates).ToList()); return(result); }
public List<ICommentNode> Build(CommentTree tree, CommentTreeContext treeContext, User currentUser) { var wrapped = _commentWrapper.Wrap(treeContext.Comments, currentUser).ToDictionary(x => x.Comment.Id, x => new CommentNode(x)); var final = new List<ICommentNode>(); var walked = new List<Guid>(); // lets mark any comments as collapsed if needed foreach (var comment in wrapped.Values) { // TODO: make this configurable per-user int minimumScore = 0; if ((comment.Comment.Author != null && currentUser != null) && currentUser.Id == comment.Comment.Author.Id) { // the current user is the author, don't collapse! comment.Collapsed = false; } else if (comment.Comment.Score < minimumScore) { // too many down votes to show to the user comment.Collapsed = true; } else { // the current user is not the author, and we have enough upvotes to display, // don't collapse comment.Collapsed = false; } } foreach (var comment in wrapped.Values) { comment.NumberOfChildren = treeContext.CommentsChildrenCount[comment.Comment.Comment.Id]; CommentNode parent = null; if (comment.Comment.Comment.ParentId.HasValue) parent = wrapped.ContainsKey(comment.Comment.Comment.ParentId.Value) ? wrapped[comment.Comment.Comment.ParentId.Value] : null; if (comment.Comment.Comment.ParentId.HasValue && treeContext.Comments.Contains(comment.Comment.Comment.ParentId.Value)) comment.IsParentVisible = true; if (parent != null && comment.Comment.CurrentUserIsAuthor) { // this comment is the current user, so lets walk the parents // and uncollapse any comments which may be collapsed var ancestor = parent; while (ancestor != null && !walked.Contains(ancestor.Comment.Comment.Id)) { ancestor.Collapsed = false; walked.Add(ancestor.Comment.Comment.Id); ancestor = (ancestor.Comment.Comment.ParentId.HasValue && wrapped.ContainsKey(comment.Comment.Comment.ParentId.Value)) ? wrapped[comment.Comment.Comment.ParentId.Value] : null; } } if (treeContext.MoreRecursion.Contains(comment.Comment.Comment.Id)) comment.Children.Add(new MoreRecursionNode(comment.Comment)); if (parent != null) { comment.Parent = comment.Comment; parent.Children.Add(comment); } else { if (comment.Comment.Comment.ParentId.HasValue) { // we don't have a parent here, but this comment does have a parent. // we need to get it comment.Parent = _commentWrapper.Wrap(comment.Comment.Comment.ParentId.Value); } final.Add(comment); } } foreach (var visibleId in wrapped.Keys) { // this item is already scheduled to have a new link to see all the children if (treeContext.MoreRecursion.Contains(visibleId)) continue; var children = tree.Tree.ContainsKey(visibleId) ? tree.Tree[visibleId] : new List<Guid>(); var missingChildren = children.Where(x => !treeContext.Comments.Contains(x)).ToList(); if (missingChildren.Count > 0) { var visibleChildren = children.Where(x => treeContext.Comments.Contains(x)).ToList(); var visibleCount = visibleChildren.Sum(x => (treeContext.CommentsChildrenCount[x]) + 1); var missingCount = treeContext.CommentsChildrenCount[visibleId] - visibleCount; var missingDepth = (tree.Depth.ContainsKey(visibleId) ? tree.Depth[visibleId] : 0) + 1 - treeContext.OffsetDepth; var moreChildren = new MoreChildren(); moreChildren.ChildComments.AddRange(missingChildren); moreChildren.MissingCount = missingCount; moreChildren.PostId = tree.PostId; moreChildren.Sort = treeContext.Sort; moreChildren.Depth = missingDepth; wrapped[visibleId].Children.Add(moreChildren); } } if (treeContext.TopLevelCandidates.Count > 0) { var moreChildren = new MoreChildren(); moreChildren.ChildComments.AddRange(treeContext.TopLevelCandidates); moreChildren.MissingCount = moreChildren.ChildComments.Sum(x => (treeContext.CommentsChildrenCount.ContainsKey(x) ? treeContext.CommentsChildrenCount[x] : 0) + 1); moreChildren.PostId = tree.PostId; moreChildren.Sort = treeContext.Sort; moreChildren.Depth = 0; final.Add(moreChildren); } return final; }
public CommentBuilder(CommentTree commentTree) { _tree = commentTree; }