Comment posting support.
authorEevee <git@veekun.com>
Thu, 15 Oct 2009 07:20:48 +0000 (00:20 -0700)
committerEevee <git@veekun.com>
Thu, 15 Oct 2009 07:20:48 +0000 (00:20 -0700)
12 files changed:
floof/config/routing.py
floof/controllers/art.py
floof/controllers/comments.py [new file with mode: 0644]
floof/lib/base.py
floof/lib/helpers.py
floof/model/comments.py
floof/templates/art/show.mako
floof/templates/comments.mako [deleted file]
floof/templates/comments/lib.mako [new file with mode: 0644]
floof/templates/comments/reply.mako [new file with mode: 0644]
floof/templates/comments/thread.mako [new file with mode: 0644]
floof/tests/functional/test_comments.py [new file with mode: 0644]

index ffce2d6..5f729e6 100644 (file)
@@ -46,6 +46,11 @@ def make_map():
     map.connect('/users', controller='users', action='list')
     map.connect('user_page', '/users/{name}', controller='users', action='view')
 
+    # Comments
+    with map.submapper(controller='comments') as sub:
+        sub.connect('/*owner_url/comments', action='thread')
+        sub.connect('/*owner_url/comments/reply', action='reply')
+        sub.connect('/*owner_url/comments/reply_done', action='reply_done', **require_POST)
 
     with map.submapper(controller="art") as sub:
         sub.connect('new_art',      '/art/new',         action="new")
index ca1d7dc..9576109 100644 (file)
@@ -9,6 +9,7 @@ log = logging.getLogger(__name__)
 
 import elixir
 from floof.model.art import Art, Rating
+from floof.model.comments import Discussion
 
 from sqlalchemy.exceptions import IntegrityError
 
@@ -31,6 +32,7 @@ class ArtController(BaseController):
     # TODO: login required
     def create(self):
         c.art = Art(uploader=c.user, **request.params)
+        c.art.discussion = Discussion(count=0)
 
         try:
             elixir.session.commit()
diff --git a/floof/controllers/comments.py b/floof/controllers/comments.py
new file mode 100644 (file)
index 0000000..03aee3d
--- /dev/null
@@ -0,0 +1,62 @@
+import logging
+
+import elixir
+from pylons import config, request, response, session, tmpl_context as c
+from pylons.controllers.util import abort, redirect, redirect_to
+
+from floof.lib.base import BaseController, render
+from floof.model.art import Art
+from floof.model.comments import Comment
+
+log = logging.getLogger(__name__)
+
+def find_owner(owner_url):
+    """Returns whatever thing owns a group of comments."""
+
+    # Need to prepend a slash to make this an absolute URL
+    route = config['routes.map'].match('/' + owner_url)
+
+    if route['action'] not in ('show', 'view'):
+        abort(404)
+
+    if route['controller'] == 'art':
+        model = Art
+    else:
+        abort(404)
+
+    owner = model.query.get(route['id'])
+    if not owner:
+        abort(404)
+
+    return owner
+
+
+class CommentsController(BaseController):
+
+    def thread(self, owner_url):
+        """View a thread of comments, either attached to an item or starting
+        from a parent comment belonging to that item.
+        """
+        owner_object = find_owner(owner_url)
+        c.comments = owner_object.discussion.comments
+        return render('/comments/thread.mako')
+
+    def reply(self, owner_url):
+        """Reply to a comment or discussion."""
+        return render('/comments/reply.mako')
+
+    def reply_done(self, owner_url):
+        """Finish replying to a comment or discussion."""
+        # XXX form validation woo
+
+        new_comment = Comment(
+            text=request.params['text'],
+            user=c.user,
+        )
+
+        owner_object = find_owner(owner_url)
+        discussion = owner_object.discussion
+        discussion.comments.append(new_comment)
+        elixir.session.commit()
+
+        return redirect('/' + owner_url, code=301)
index d05c24d..169493c 100644 (file)
@@ -4,16 +4,18 @@ Provides the BaseController class for subclassing.
 """
 from pylons.controllers import WSGIController
 from pylons.templating import render_mako as render
-from pylons import config
-from floof import model
+from pylons import config, session, tmpl_context as c
+from routes import request_config
 
-from pylons import session, tmpl_context as c
+from floof import model
 from floof.model.users import User
 
 class BaseController(WSGIController):
 
     # NOTE: This could have been implemented as a middleware =]
     def __before__(self):
+        c.route = request_config().mapper_dict
+
         # Fetch current user object
         try:
             c.user = User.query.get(session['user_id'])
index c8a1251..1c2f0c1 100644 (file)
@@ -31,3 +31,9 @@ def get_object_or_404(model, **kw):
         abort(404)
     return obj
 
+def get_comment_owner_url(**route):
+    """Given a view route, returns the owner_url route parameter for generating
+    comment URLs.
+    """ 
+    # url() returns URLs beginning with a slash.  We just need to strip it.
+    return url(**route)[1:]
index f46b37d..4504b6f 100644 (file)
@@ -1,3 +1,5 @@
+import datetime
+
 from elixir import *
 
 class Discussion(Entity):
@@ -6,6 +8,8 @@ class Discussion(Entity):
     comments = OneToMany('Comment')
 
 class Comment(Entity):
-    discussion = ManyToOne('Discussion')
+    time = Field(DateTime, default=datetime.datetime.now)
     text = Field(Unicode(65536))
 
+    discussion = ManyToOne('Discussion')
+    user = ManyToOne('User')
index 5895be8..cf713dc 100644 (file)
@@ -1,5 +1,5 @@
 <%inherit file="/base.mako" />
-<%namespace name="comments" file="/comments.mako" />
+<%namespace name="comments" file="/comments/lib.mako" />
 
 <%! from floof.model.art import Rating %>
 
@@ -34,4 +34,4 @@ ${h.end_form()}
 
 <img class="full" src="${c.art.get_path()}">
 
-${comments.entire_thread(c.art.discussion)}
+${comments.comment_block(c.art.discussion.comments)}
diff --git a/floof/templates/comments.mako b/floof/templates/comments.mako
deleted file mode 100644 (file)
index cc59b54..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<%def name="entire_thread(discussion)">
-<%
-    if not discussion:
-        return
-%>\
-<ul>
-    % for comment in discussion.comments:
-    <li>${comment.text}</li>
-    % endfor
-</ul>
-</%def>
diff --git a/floof/templates/comments/lib.mako b/floof/templates/comments/lib.mako
new file mode 100644 (file)
index 0000000..df5cbf6
--- /dev/null
@@ -0,0 +1,15 @@
+<%def name="comment_block(comments)">
+<p><a href="${url(controller='comments', action='thread', owner_url=h.get_comment_owner_url(**c.route))}">View all</a></p>
+<p><a href="${url(controller='comments', action='reply', owner_url=h.get_comment_owner_url(**c.route))}">Reply</a></p>
+${comment_thread(comments)}
+</%def>
+
+<%def name="comment_thread(comments)">
+% for comment in comments:
+<div class="comment">
+    <div class="user">${comment.user.name}</div>
+    <div class="time">${comment.time}</div>
+    <p>${comment.text}</p>
+</div>
+% endfor
+</%def>
diff --git a/floof/templates/comments/reply.mako b/floof/templates/comments/reply.mako
new file mode 100644 (file)
index 0000000..9941433
--- /dev/null
@@ -0,0 +1,12 @@
+<%inherit file="/base.mako" />
+<%namespace name="comments" file="/comments/lib.mako" />
+
+<h1>Reply</h1>
+${h.form(url(controller='comments', action='reply_done', owner_url=c.owner_url), method='post')}
+<dl class="form">
+    <dt>Comment</dt>
+    <dd>${h.textarea('text')}</dd>
+
+    <dd>${h.submit(None, 'Post')}</dd>
+</dl>
+${h.end_form()}
diff --git a/floof/templates/comments/thread.mako b/floof/templates/comments/thread.mako
new file mode 100644 (file)
index 0000000..1f01295
--- /dev/null
@@ -0,0 +1,5 @@
+<%inherit file="/base.mako" />
+<%namespace name="comments" file="/comments/lib.mako" />
+
+<h1>Comments</h1>
+${comments.comment_thread(c.comments)}
diff --git a/floof/tests/functional/test_comments.py b/floof/tests/functional/test_comments.py
new file mode 100644 (file)
index 0000000..908d1bc
--- /dev/null
@@ -0,0 +1,7 @@
+from floof.tests import *
+
+class TestCommentsController(TestController):
+
+    def test_index(self):
+        response = self.app.get(url(controller='comments', action='index'))
+        # Test response...