From cde7a4e01fa2e0f98b6af2ac5c607ed2f5711d6a Mon Sep 17 00:00:00 2001 From: blankie Date: Thu, 7 Sep 2023 09:59:03 +1000 Subject: [PATCH 1/2] Add a newest reply/newest leaf sorting method for comments Implements #111 --- tildes/tildes/enums.py | 3 +++ tildes/tildes/models/comment/comment_tree.py | 25 ++++++++++++++------ tildes/tildes/views/topic.py | 11 +++++---- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/tildes/tildes/enums.py b/tildes/tildes/enums.py index cb5792a..46b9ec6 100644 --- a/tildes/tildes/enums.py +++ b/tildes/tildes/enums.py @@ -45,6 +45,7 @@ class CommentTreeSortOption(enum.Enum): NEWEST = enum.auto() POSTED = enum.auto() RELEVANCE = enum.auto() + NEWEST_REPLY = enum.auto() @property def description(self) -> str: @@ -55,6 +56,8 @@ class CommentTreeSortOption(enum.Enum): return "order posted" elif self.name == "RELEVANCE": return "relevance" + elif self.name == "NEWEST_REPLY": + return "newest reply" return "most {}".format(self.name.lower()) diff --git a/tildes/tildes/models/comment/comment_tree.py b/tildes/tildes/models/comment/comment_tree.py index 0fc4a25..85a6d2f 100644 --- a/tildes/tildes/models/comment/comment_tree.py +++ b/tildes/tildes/models/comment/comment_tree.py @@ -100,6 +100,15 @@ class CommentTree: compare equal on the sorting method will be the same as the order that they were originally in when passed to this function. """ + # sort the tree's comments first, this will be important when sorting by newest + # reply + for comment in tree: + if not comment.has_visible_descendant: + # no need to bother sorting replies if none will be visible + continue + + comment.replies = CommentTree._sort_tree(comment.replies, sort) + if sort == CommentTreeSortOption.NEWEST: tree = sorted(tree, key=lambda c: c.created_time, reverse=True) elif sort == CommentTreeSortOption.POSTED: @@ -108,13 +117,15 @@ class CommentTree: tree = sorted(tree, key=lambda c: c.num_votes, reverse=True) elif sort == CommentTreeSortOption.RELEVANCE: tree = sorted(tree, key=lambda c: c.relevance_sorting_value, reverse=True) - - for comment in tree: - if not comment.has_visible_descendant: - # no need to bother sorting replies if none will be visible - continue - - comment.replies = CommentTree._sort_tree(comment.replies, sort) + elif sort == CommentTreeSortOption.NEWEST_REPLY: + # sort by the creation time of the most recent reply in the entire tree, or + # the comment itself if it has no children. the comment's first reply is + # the newest reply since it has been sorted above + tree = sorted( + tree, + key=lambda c: (c.replies[0] if c.replies else c).created_time, + reverse=True, + ) return tree diff --git a/tildes/tildes/views/topic.py b/tildes/tildes/views/topic.py index cba2c7f..376cd8e 100644 --- a/tildes/tildes/views/topic.py +++ b/tildes/tildes/views/topic.py @@ -184,10 +184,13 @@ def get_group_topics( # noqa groups = [request.context] if request.user: - groups.extend([ - sub.group for sub in request.user.subscriptions - if sub.group.is_subgroup_of(request.context) - ]) + groups.extend( + [ + sub.group + for sub in request.user.subscriptions + if sub.group.is_subgroup_of(request.context) + ] + ) include_subgroups = all_subgroups else: From ad00abe067b3184daafe133d31d90633a917e234 Mon Sep 17 00:00:00 2001 From: blankie Date: Mon, 4 Mar 2024 19:11:14 +1100 Subject: [PATCH 2/2] Properly sort by newest reply The previous algorithm would fail with this order of comments: - Comment 1 - Comment 2 - Comment 4 - Comment 3 --- tildes/tildes/models/comment/comment_tree.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tildes/tildes/models/comment/comment_tree.py b/tildes/tildes/models/comment/comment_tree.py index 85a6d2f..e56659a 100644 --- a/tildes/tildes/models/comment/comment_tree.py +++ b/tildes/tildes/models/comment/comment_tree.py @@ -92,6 +92,13 @@ class CommentTree: comment.depth = 0 self.tree.append(comment) + @staticmethod + def _first_bottommost_reply(comment: Comment) -> Comment: + """Continuously gets the first reply from a comment until there is no more.""" + while comment.replies: + comment = comment.replies[0] + return comment + @staticmethod def _sort_tree(tree: list[Comment], sort: CommentTreeSortOption) -> list[Comment]: """Sort the tree by the desired ordering (recursively). @@ -118,12 +125,13 @@ class CommentTree: elif sort == CommentTreeSortOption.RELEVANCE: tree = sorted(tree, key=lambda c: c.relevance_sorting_value, reverse=True) elif sort == CommentTreeSortOption.NEWEST_REPLY: - # sort by the creation time of the most recent reply in the entire tree, or - # the comment itself if it has no children. the comment's first reply is - # the newest reply since it has been sorted above + # sort by the creation time of the first bottom-most reply in the + # entire tree, or the comment itself if there are no replies. + # the comment's first bottom-most reply is the newest reply since + # it has been sorted above tree = sorted( tree, - key=lambda c: (c.replies[0] if c.replies else c).created_time, + key=lambda c: CommentTree._first_bottommost_reply(c).created_time, reverse=True, )