From fca6f64bc81a02c61ba45a13de25f3da2e7630b3 Mon Sep 17 00:00:00 2001 From: Eevee Date: Thu, 15 Oct 2009 00:20:48 -0700 Subject: [PATCH] Comment posting support. --- floof/config/routing.py | 5 +++ floof/controllers/art.py | 2 ++ floof/controllers/comments.py | 62 +++++++++++++++++++++++++++++++++ floof/lib/base.py | 8 +++-- floof/lib/helpers.py | 6 ++++ floof/model/comments.py | 6 +++- floof/templates/art/show.mako | 4 +-- floof/templates/comments.mako | 11 ------ floof/templates/comments/lib.mako | 15 ++++++++ floof/templates/comments/reply.mako | 12 +++++++ floof/templates/comments/thread.mako | 5 +++ floof/tests/functional/test_comments.py | 7 ++++ 12 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 floof/controllers/comments.py delete mode 100644 floof/templates/comments.mako create mode 100644 floof/templates/comments/lib.mako create mode 100644 floof/templates/comments/reply.mako create mode 100644 floof/templates/comments/thread.mako create mode 100644 floof/tests/functional/test_comments.py diff --git a/floof/config/routing.py b/floof/config/routing.py index ffce2d6..5f729e6 100644 --- a/floof/config/routing.py +++ b/floof/config/routing.py @@ -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") diff --git a/floof/controllers/art.py b/floof/controllers/art.py index ca1d7dc..9576109 100644 --- a/floof/controllers/art.py +++ b/floof/controllers/art.py @@ -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 index 0000000..03aee3d --- /dev/null +++ b/floof/controllers/comments.py @@ -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) diff --git a/floof/lib/base.py b/floof/lib/base.py index d05c24d..169493c 100644 --- a/floof/lib/base.py +++ b/floof/lib/base.py @@ -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']) diff --git a/floof/lib/helpers.py b/floof/lib/helpers.py index c8a1251..1c2f0c1 100644 --- a/floof/lib/helpers.py +++ b/floof/lib/helpers.py @@ -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:] diff --git a/floof/model/comments.py b/floof/model/comments.py index f46b37d..4504b6f 100644 --- a/floof/model/comments.py +++ b/floof/model/comments.py @@ -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') diff --git a/floof/templates/art/show.mako b/floof/templates/art/show.mako index 5895be8..cf713dc 100644 --- a/floof/templates/art/show.mako +++ b/floof/templates/art/show.mako @@ -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()} -${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 index cc59b54..0000000 --- a/floof/templates/comments.mako +++ /dev/null @@ -1,11 +0,0 @@ -<%def name="entire_thread(discussion)"> -<% - if not discussion: - return -%>\ - - diff --git a/floof/templates/comments/lib.mako b/floof/templates/comments/lib.mako new file mode 100644 index 0000000..df5cbf6 --- /dev/null +++ b/floof/templates/comments/lib.mako @@ -0,0 +1,15 @@ +<%def name="comment_block(comments)"> +

View all

+

Reply

+${comment_thread(comments)} + + +<%def name="comment_thread(comments)"> +% for comment in comments: +
+
${comment.user.name}
+
${comment.time}
+

${comment.text}

+
+% endfor + diff --git a/floof/templates/comments/reply.mako b/floof/templates/comments/reply.mako new file mode 100644 index 0000000..9941433 --- /dev/null +++ b/floof/templates/comments/reply.mako @@ -0,0 +1,12 @@ +<%inherit file="/base.mako" /> +<%namespace name="comments" file="/comments/lib.mako" /> + +

Reply

+${h.form(url(controller='comments', action='reply_done', owner_url=c.owner_url), method='post')} +
+
Comment
+
${h.textarea('text')}
+ +
${h.submit(None, 'Post')}
+
+${h.end_form()} diff --git a/floof/templates/comments/thread.mako b/floof/templates/comments/thread.mako new file mode 100644 index 0000000..1f01295 --- /dev/null +++ b/floof/templates/comments/thread.mako @@ -0,0 +1,5 @@ +<%inherit file="/base.mako" /> +<%namespace name="comments" file="/comments/lib.mako" /> + +

Comments

+${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 index 0000000..908d1bc --- /dev/null +++ b/floof/tests/functional/test_comments.py @@ -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... -- 2.7.4