From af2fcba5c4ce16bde1a2267b95803bc2afc9e572 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 7 Jul 2011 18:04:19 +0200 Subject: [PATCH 1/2] Issue #431 - Prevent comment link expiry - Added functionality for comment linking * `media.html` * Changed comment textarea handle from `comment` => `field_comment` * Active comment is hilighted with the CSS class name `comment_active` and also with the hyperlink anchor #comment * Changed media.html so that pagination always uses Route('mediagoblin.user_pages.media_home') as base_url * `user_pages/forms.py` * Renamed MediaComment form field `comment` => `field_comment` * `user_pages/routing.py` * Added route for `/u/joar/m/123..456/c/234..567/`, points to `media_home` * `user_pages/views.py` * `media_home` now checks if the request contains a comment id parameter then acts accordingly with pagination whether to call it with a `jump_to_id` or not. * `media_post_comment` - Updated MediaCommentForm field name `comment` => `field_comment` * `util.py` * `redirect` now supports querystring arguments. - NOT USED (should we keep it? I think so, it might be useful, sometime [don't call me a code hoarder]). * `Pagination.__init__` now accepts one further argument, the `jump_to_id`. It assist the comment linking functionality in finding and returning the proper page for a comment. This feature will work for all kinds of objects. It might not be optimal, but it is well functional :) --- .../mediagoblin/user_pages/media.html | 19 +++++++--- mediagoblin/user_pages/forms.py | 4 +-- mediagoblin/user_pages/routing.py | 3 ++ mediagoblin/user_pages/views.py | 10 ++++-- mediagoblin/util.py | 36 ++++++++++++++++--- 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 1484cc73..477eae61 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -55,7 +55,7 @@
- {{ wtforms_util.render_field_div(comment_form.comment) }} + {{ wtforms_util.render_field_div(comment_form.field_comment) }}
@@ -65,7 +65,12 @@ {% if comments %} {% for comment in comments %} {% set comment_author = comment.author() %} -
+ {% if pagination.active_id == comment._id %} +
+ + {% else %} + {% endif %}
diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 9f7d2fbd..b234d739 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -17,5 +17,5 @@ import wtforms class MediaCommentForm(wtforms.Form): - comment = wtforms.TextAreaField('Comment', - [wtforms.validators.Required()]) \ No newline at end of file + field_comment = wtforms.TextAreaField('Comment', + [wtforms.validators.Required()]) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 255b6f66..3be0617d 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -24,6 +24,9 @@ user_routes = [ Route('mediagoblin.user_pages.media_home', '/{user}/m/{media}/', requirements=dict(m_id="[0-9a-fA-F]{24}"), controller="mediagoblin.user_pages.views:media_home"), + Route('mediagoblin.user_pages.media_home.view_comment', + '/{user}/m/{media}/c/{comment}/', + controller="mediagoblin.user_pages.views:media_home"), Route('mediagoblin.edit.edit_media', "/{user}/m/{media}/edit/", controller="mediagoblin.edit.views:edit_media"), Route('mediagoblin.user_pages.atom_feed', '/{user}/atom/', diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 3a8684d3..ca1060a3 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -95,8 +95,14 @@ def media_home(request, media, page, **kwargs): """ 'Homepage' of a MediaEntry() """ + if ObjectId(request.matchdict.get('comment')): + pagination = Pagination( + page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE, + ObjectId(request.matchdict.get('comment'))) + else: + pagination = Pagination( + page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE) - pagination = Pagination(page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE) comments = pagination() comment_form = user_forms.MediaCommentForm(request.POST) @@ -118,7 +124,7 @@ def media_post_comment(request): comment = request.db.MediaComment() comment['media_entry'] = ObjectId(request.matchdict['media']) comment['author'] = request.user['_id'] - comment['content'] = request.POST['comment'] + comment['content'] = request.POST['field_comment'] comment['content_html'] = cleaned_markdown_conversion(comment['content']) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index ab219df0..7b1e4a2a 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from __future__ import division + from email.MIMEText import MIMEText import gettext import pkg_resources @@ -21,7 +23,7 @@ import smtplib import sys import re import urllib -from math import ceil +from math import ceil, floor import copy from babel.localedata import exists @@ -35,6 +37,8 @@ from mediagoblin import mg_globals from mediagoblin import messages from mediagoblin.db.util import ObjectId +from itertools import izip, count + TESTS_ENABLED = False def _activate_testing(): """ @@ -133,7 +137,16 @@ def render_to_response(request, template, context): def redirect(request, *args, **kwargs): """Returns a HTTPFound(), takes a request and then urlgen params""" - return exc.HTTPFound(location=request.urlgen(*args, **kwargs)) + + querystring = None + if kwargs.get('querystring'): + querystring = kwargs.get('querystring') + del kwargs['querystring'] + + return exc.HTTPFound( + location=''.join([ + request.urlgen(*args, **kwargs), + querystring if querystring else ''])) def setup_user_in_request(request): @@ -418,7 +431,8 @@ class Pagination(object): get actual data slice through __call__(). """ - def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE): + def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE, + jump_to_id=False): """ Initializes Pagination @@ -426,11 +440,25 @@ class Pagination(object): - page: requested page - per_page: number of objects per page - cursor: db cursor + - jump_to_id: ObjectId, sets the page to the page containing the object + with _id == jump_to_id. """ - self.page = page + self.page = page self.per_page = per_page self.cursor = cursor self.total_count = self.cursor.count() + self.active_id = None + + if jump_to_id: + cursor = copy.copy(self.cursor) + + for (doc, increment) in izip(cursor, count(0)): + if doc['_id'] == jump_to_id: + self.page = 1 + int(floor(increment / self.per_page)) + + self.active_id = jump_to_id + break + def __call__(self): """ From f646f5d36df0730a8c34019dfcc37cca31cc6bb6 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 7 Jul 2011 22:45:51 +0200 Subject: [PATCH 2/2] Updated `MediaCommentForm.field_comment` => `MediaCommentForm.comment_content` * Also changed file encoding of `user_pages/forms.py` from dos to unix. --- .../mediagoblin/user_pages/media.html | 2 +- mediagoblin/user_pages/forms.py | 43 ++++++++++--------- mediagoblin/user_pages/views.py | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 477eae61..3f4dce3b 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -55,7 +55,7 @@ - {{ wtforms_util.render_field_div(comment_form.field_comment) }} + {{ wtforms_util.render_field_div(comment_form.comment_content) }}
diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index b234d739..8829b674 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -1,21 +1,22 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import wtforms - -class MediaCommentForm(wtforms.Form): - field_comment = wtforms.TextAreaField('Comment', - [wtforms.validators.Required()]) +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import wtforms + +class MediaCommentForm(wtforms.Form): + comment_content = wtforms.TextAreaField( + 'Comment', + [wtforms.validators.Required()]) diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index ca1060a3..a3172ebd 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -124,7 +124,7 @@ def media_post_comment(request): comment = request.db.MediaComment() comment['media_entry'] = ObjectId(request.matchdict['media']) comment['author'] = request.user['_id'] - comment['content'] = request.POST['field_comment'] + comment['content'] = request.POST['comment_content'] comment['content_html'] = cleaned_markdown_conversion(comment['content'])