From: Eevee Date: Fri, 16 Oct 2009 05:44:57 +0000 (-0700) Subject: Added partial support for comment threading. X-Git-Url: http://git.veekun.com/zzz-floof.git/commitdiff_plain/c68928f2fc57638134bae50fe4ff5b1e979bb198?ds=inline Added partial support for comment threading. --- diff --git a/floof/controllers/comments.py b/floof/controllers/comments.py index 03aee3d..70c9073 100644 --- a/floof/controllers/comments.py +++ b/floof/controllers/comments.py @@ -49,14 +49,13 @@ class CommentsController(BaseController): """Finish replying to a comment or discussion.""" # XXX form validation woo + owner_object = find_owner(owner_url) + new_comment = Comment( text=request.params['text'], user=c.user, + discussion=owner_object.discussion, ) - - owner_object = find_owner(owner_url) - discussion = owner_object.discussion - discussion.comments.append(new_comment) elixir.session.commit() return redirect('/' + owner_url, code=301) diff --git a/floof/model/comments.py b/floof/model/comments.py index 4504b6f..e1ad150 100644 --- a/floof/model/comments.py +++ b/floof/model/comments.py @@ -1,15 +1,62 @@ import datetime from elixir import * +from sqlalchemy import func class Discussion(Entity): """Represents a collection of comments attached to some other object.""" count = Field(Integer) - comments = OneToMany('Comment') + comments = OneToMany('Comment', order_by='left') class Comment(Entity): time = Field(DateTime, default=datetime.datetime.now) text = Field(Unicode(65536)) + # Comments are a tree, and are stored as a nested set, because: + # - It's easy to get a subtree with a single query. + # - It's easy to get a comment's depth. + # - It's easy to sort comments without recursion. + # The only real disadvantage is that adding a comment requires a quick + # update of all the following comments (in post-order), but that's rare + # enough that it shouldn't be a problem. + left = Field(Integer, index=True) + right = Field(Integer) + discussion = ManyToOne('Discussion') user = ManyToOne('User') + + def __init__(self, parent=None, **kwargs): + """Constructor override to set left/right correctly on a new comment. + """ + super(Comment, self).__init__(**kwargs) + + # Keep the comment count updated + self.discussion.count += 1 + + if parent: + # Parent comment given. Add this comment just before the parent's + # right side... + self.left = parent.right + self.right = parent.right + 1 + + # ...then adjust all rightward comments accordingly + Comment.query.filter(Comment.discussion == self.discussion) \ + .filter(Comment.right > parent.right) \ + .update({ Comment.left: Comment.left + 2, + Comment.right: Comment.right + 2 }) + + # And, finally, update the parent's right endpoint + parent.right += 2 + + else: + query = session.query(func.max(Comment.right)) \ + .filter(Comment.discussion == self.discussion) + (max_right,) = query.one() + + if not max_right: + # No comments yet. Use 1 and 2 + self.left = 1 + self.right = 2 + else: + self.left = max_right + 1 + self.right = max_right + 2 diff --git a/floof/templates/comments/lib.mako b/floof/templates/comments/lib.mako index df5cbf6..38e6534 100644 --- a/floof/templates/comments/lib.mako +++ b/floof/templates/comments/lib.mako @@ -1,4 +1,6 @@ <%def name="comment_block(comments)"> +

${len(comments)} comments

+## XXX make sure these do the right thing when this is a subtree

View all

Reply

${comment_thread(comments)} diff --git a/floof/templates/comments/thread.mako b/floof/templates/comments/thread.mako index 1f01295..7b3580a 100644 --- a/floof/templates/comments/thread.mako +++ b/floof/templates/comments/thread.mako @@ -1,5 +1,4 @@ <%inherit file="/base.mako" /> <%namespace name="comments" file="/comments/lib.mako" /> -

Comments

-${comments.comment_thread(c.comments)} +${comments.comment_block(c.comments)}