From 3a0e7fc3fa648401d7373499fca420d37598681c Mon Sep 17 00:00:00 2001 From: Deimos Date: Thu, 10 Oct 2019 19:01:44 -0600 Subject: [PATCH] Compress fully-removed comment chains When a chain of comments has been fully removed, this will display a single marker like "Removed by admin: 8 comments by 2 users" instead of individual "Comment removed by site admin" markers for each one. --- tildes/tildes/models/comment/comment_tree.py | 34 +++++++++++++++++++ .../tildes/templates/macros/comments.jinja2 | 11 ++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/tildes/tildes/models/comment/comment_tree.py b/tildes/tildes/models/comment/comment_tree.py index 5ba3386..107d84f 100644 --- a/tildes/tildes/models/comment/comment_tree.py +++ b/tildes/tildes/models/comment/comment_tree.py @@ -3,6 +3,7 @@ """Contains the CommentTree and CommentInTree classes.""" +from collections import Counter from datetime import datetime from typing import Iterator, List, Optional, Sequence, Tuple @@ -51,6 +52,8 @@ class CommentTree: self.tree = self._prune_empty_branches(self.tree) + self._add_removed_markers() + self._count_children() def _count_children(self) -> None: @@ -131,6 +134,37 @@ class CommentTree: return pruned_tree + def _add_removed_markers(self) -> None: + """Add markers to chains of removed comments with more info. + + When displaying a comment tree, these markers should be displayed to users + that can't view the removed comment, and stop recursing down the branch. + """ + # work backwards so all replies are always processed first + for comment in reversed(self.comments): + if not comment.is_removed: + continue + + # we can only compress when all descendants are also removed - checking + # for this attr works because it's only added after passing this check + if not all( + hasattr(reply, "removed_comments_by_user") for reply in comment.replies + ): + continue + + comment.removed_comments_by_user = Counter({comment.user: 1}) + + # add all the descendants' counts onto this comment's + for reply in comment.replies: + comment.removed_comments_by_user += reply.removed_comments_by_user + + num_comments = sum(comment.removed_comments_by_user.values()) + num_users = len(comment.removed_comments_by_user) + if num_comments > 1: + comment.removed_marker = ( + f"Removed by admin: {num_comments} comments by {num_users} users" + ) + def __iter__(self) -> Iterator[Comment]: """Iterate over the (top-level) Comments in the tree.""" for comment in self.tree: diff --git a/tildes/tildes/templates/macros/comments.jinja2 b/tildes/tildes/templates/macros/comments.jinja2 index 8ae7531..8944ca4 100644 --- a/tildes/tildes/templates/macros/comments.jinja2 +++ b/tildes/tildes/templates/macros/comments.jinja2 @@ -30,9 +30,10 @@ > {{ render_comment_contents(comment, is_individual_comment) }} - {% if comment.replies is defined and comment.replies %} + {# Recursively display reply comments, unless we hit a "removed marker" #} + {% if comment.replies and + (request.has_permission("view", comment) or not comment.removed_marker) %}
    - {# Recursively display reply comments #} {{ loop(comment.replies) }}
{% endif %} @@ -74,7 +75,11 @@ {% if comment.is_deleted %}
Comment deleted by author
{% elif comment.is_removed %} -
Comment removed by site admin
+ {% if comment.removed_marker %} +
{{ comment.removed_marker }}
+ {% else %} +
Comment removed by site admin
+ {% endif %} {% endif %} {% endif %}