murarth avatar murarth committed c158c4a

Limit comment listing by depth

Comments (0)

Files changed (4)

reddish/controllers/community.py

         return self._render('community/bans', { 'bans': cmty.get_bans() })
 
     @get
-    @v.validate(cmty = v.Community('community'), post = v.Post('post'))
-    def comments(self, cmty, post):
+    @v.validate(cmty = v.Community('community'), post = v.Post('post'),
+        limit = v.IntRange('limit', min = 1, max = 500,
+            required = False, default = 500))
+    def comments(self, cmty, post, limit):
         post.belongs_to(cmty)
         c.active_tab = 'comments'
         return self._render('community/comments',
-            { 'post': post, 'comments': post.get_comments(c.user) })
+            { 'post': post, 'comments': post.get_comments(c.user, limit) })
 
     @get
     @v.validate(v.LoggedIn, cmty = v.Moderates('community'))
     @get
     @v.validate(cmty = v.Community('community'),
         post = v.Post('post'), comment = v.Comment('comment'),
-        context = v.Int('context', required = False))
-    def view_comment(self, cmty, post, comment, context):
+        context = v.IntRange('context', min = 0, max = 9,
+            required = False, default = 0),
+        limit = v.IntRange('limit', min = 1, max = 500,
+            required = False, default = 100))
+    def view_comment(self, cmty, post, comment, context, limit):
         post.belongs_to(cmty)
         comment.belongs_to(cmty)
 
-        comment.construct_tree(c.user)
-
         c.hilight_comment = comment
 
-        if context and context > 0:
-            c.comment_context = context
-            for cid in comment.parents[:-context - 1:-1]:
-                cm = model.Comment.get(cid)
-                cm.replies = [comment]
-                comment = cm
-        else:
-            c.comment_context = 0
+        comment = comment.get_context(c.user, context, limit = limit)
+        c.comment_context = context
 
         return self._render('community/comments',
             { 'post': post, 'comments': [comment] })

reddish/model/__init__.py

         if self.removed:
             return User.get(self.removed)
 
-    def get_comments(self, user = None):
-        # TODO: Varying types of comment sorting
+    def get_comments(self, user = None, limit = 500):
+        # TODO: Sort by 'new' or 'latest'
         return Comment.comment_tree(user,
-            Comment.find(post = self._id)
-                .sort([('total_value', -1), ('created', 1)]).limit(500))
+            Comment.find(post = self._id, depth = { '$lt': 10 })
+                .sort([('total_value', -1), ('created', 1)]).limit(limit))
 
     def get_community(self):
         return Community.get(self.community)
     ## List of parent Comment _ids, beginning with root comment;
     # empty for root comments
     parents = mongo.ListField(str)
+    ## Number of parent Comments
+    depth = mongo.Field(int, default = 0)
     ## Number of direct replies
     num_replies = mongo.Field(int, default = 0)
+    ## Number of descendant comments
+    num_children = mongo.Field(int, default = 0)
     ## Moderator _id who approved the Comment
     approved = mongo.Field(str)
     ## Whether the Comment has been removed by a moderator
 
                 tree, tree_d = tree_d[p]
             else:
-                c.replies = replies = []
+                c._replies = replies = []
                 tree.append(c)
                 tree_d[c._id] = (replies, {})
 
         if self.community != cmty._id:
             abort(404)
 
-    def construct_tree(self, user = None):
+    def get_context(self, user = None, context = 0,
+            max_context = 9, limit = 500):
+        '''
+        Populate Comment context, fetching replies and possibly parents.
+        The topmost ancestor of the context will be returned.
+
+        user:
+            User viewing the Comment
+
+        context:
+            Number of parents to include in context
+        '''
         comments = [self]
-        comments.extend(Comment.find(parents = self._id)
-            .sort([('total_value', -1), ('created', -1)]))
-        self.comment_tree(user, comments, len(self.parents))
+        comments.extend(Comment.find(parents = self._id,
+            depth = { '$lt': max(10 + self.depth - context, 0) })
+            .sort([('total_value', -1), ('created', 1)]).limit(limit))
+        self.comment_tree(user, comments, self.depth)
+
+        if context:
+            for pid in reversed(self.parents[-context:]):
+                cm = Comment.get(pid)
+                cm._replies = [self]
+                self = cm
+
+        return self
 
     def decorate(self, user, decoration):
         decorate(self, user, decoration)
 
         if not (self.removed or self.hidden):
             self.set_value()
-            Session.update(Post, { '_id': self.post },
-                { '$inc': { 'num_comments': -1 } })
-
-            if self.parents:
-                Session.update(Comment, { '_id': { '$in': self.parents } },
-                    { '$inc': { 'num_replies': -1 } }, multi = True)
+            self.update_counts(-1)
 
         if is_admin:
             AdminLog.log(user, 'delete',
             return
 
         if not (self.deleted or self.hidden):
-            Session.update(Post, { '_id': self.post },
-                { '$inc': { 'num_comments': 1 } })
-
-            if self.parents:
-                Session.update(Comment, { '_id': { '$in': self.parents } },
-                    { '$inc': { 'num_replies': 1 } }, multi = True)
+            self.update_counts(1)
 
         self.get_community().log(mod, 'approve', comment = self._id)
 
 
         if not (self.deleted or self.hidden):
             self.set_value()
-            Session.update(Post, { '_id': self.post },
-                { '$inc': { 'num_comments': -1 } })
-
-            if self.parents:
-                Session.update(Comment, { '_id': { '$in': self.parents } },
-                    { '$inc': { 'num_replies': -1 } }, multi = True)
+            self.update_counts(-1)
 
         self.get_community().log(mod, 'remove', comment = self._id)
 
         if not self.get_community().can_comment(author):
             raise ClientError('You cannot submit comments to this community')
 
+        reply.community = self.community
+        reply.post = self.post
+        reply.parents = self.parents + [self._id]
+        reply.depth = self.depth + 1
+        reply.set_value()
+        reply._commit()
+
         if not reply.hidden:
-            Session.modify(self, { '$inc': { 'num_replies': 1 } })
-
-        try:
-            reply.community = self.community
-            reply.post = self.post
-            reply.parents = self.parents + [self._id]
-            reply.set_value()
-            reply._commit()
-        except Exception as e:
-            if not reply.hidden:
-                Session.update(Comment, { '_id': self._id },
-                    { '$inc': { 'num_replies': -1 } })
-            raise
-
-        if not reply.hidden:
-            Session.update(Post, { '_id': self.post },
-                { '$inc': { 'num_comments': 1 } })
             Session.update(Post, { '_id': self.post,
                 'last_reply': { '$lt': reply.created } },
                 { '$set': { 'last_reply': reply.created } })
 
-            if self.parents:
-                Session.update(Comment, { '_id': { '$in': self.parents } },
-                    { '$inc': { 'num_replies': 1 } }, multi = True)
+            reply.update_counts(1)
 
         if self.author and not (self.deleted or reply.hidden) and self.author != reply.author:
             try:
 
         return r
 
+    @property
+    def replies(self):
+        return getattr(self, '_replies', ())
+
+    def update_counts(self, value):
+        '''
+        Update fields in parent Post and Comments counting this Comment
+
+        value:
+            Value to add to counting fields. Either 1 or -1.
+        '''
+        Session.update(Post, { '_id': self.post },
+            { '$inc': { 'num_comments': value } })
+
+        if self.parents:
+            Session.update(Comment, { '_id': self.parents[-1] },
+                { '$inc': { 'num_replies': value } })
+            Session.update(Comment, { '_id': { '$in': self.parents } },
+                { '$inc': { 'num_children': value } }, multi = True)
+
     @classmethod
     def walk_list(cls, comments):
         [(yield i) for cmt in comments
     def walk(self):
         yield self
 
-        if hasattr(self, 'replies'):
-            for r in self.replies:
-                [(yield i) for i in r.walk()]
+        for r in self.replies:
+            [(yield i) for i in r.walk()]
 
 mongo.Index(Comment, 'author')
 mongo.Index(Comment, 'created')
+mongo.Index(Comment, 'depth')
 mongo.Index(Comment, 'parents')
 
 class Report(ModelBase, mongo.Document, Renderable):

reddish/templates/base.mako

     % endif
     ${h.ago(comment.created)}${'*' if comment.edited else '' | n}
     % if not visible:
-    % if comment.num_replies == 1:
-    <a href="#" class="expand">(${comment.num_replies} reply)</a>
-    % elif comment.num_replies:
-    <a href="#" class="expand">(${comment.num_replies} replies)</a>
+    % if comment.num_children == 1:
+    <a href="#" class="expand">(${comment.num_children} reply)</a>
+    % elif comment.num_children:
+    <a href="#" class="expand">(${comment.num_children} replies)</a>
     % endif
     % endif
 </div>
         % endif
 
         <div class="link-box">
-            <a href="${url(comment.permalink)}">permalink</a>
+            <a href="${comment.permalink}">permalink</a>
             % if c.cmty is None:
             <a href="${url(comment.permalink, context = 3)}">context</a>
             % else:
         </div>
 
         <div class="comment-replies">
-        % for r in getattr(comment, 'replies', ()):
+        <% replies = comment.replies %>
+        % for r in replies:
         ${show_comment(r, True, can_reply)}
         % endfor
+        % if len(comment.replies) < comment.num_replies:
+        <a href="${comment.permalink}">continue this thread</a>
+        % endif
         </div>
     </div>
 </div>

reddish/templates/community/comments.mako

     <% parents = len(c.hilight_comment.parents) %>
     % if parents > c.comment_context:
     <br/>
-    <a href="${url.current(context = parents)}">Show the context of this thread</a>
+    <a href="${url.current(context = min(parents, 9))}">Show the context of this thread</a>
     % endif
 </div>
 % endif
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.