Issue #431 - Prevent comment link expiry - Added functionality for comment linking
authorJoar Wandborg <git@wandborg.com>
Thu, 7 Jul 2011 16:04:19 +0000 (18:04 +0200)
committerJoar Wandborg <git@wandborg.com>
Thu, 7 Jul 2011 16:04:19 +0000 (18:04 +0200)
*   `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/templates/mediagoblin/user_pages/media.html
mediagoblin/user_pages/forms.py
mediagoblin/user_pages/routing.py
mediagoblin/user_pages/views.py
mediagoblin/util.py

index 1484cc7391f261db432483297858c20b68c0d370..477eae61fe4128ce3ec9bc43a37ba2a03ebf6f40 100644 (file)
@@ -55,7 +55,7 @@
         <form action="{{ request.urlgen('mediagoblin.user_pages.media_post_comment', 
                                          user= media.uploader().username,
                                          media=media._id) }}" method="POST">
-          {{ wtforms_util.render_field_div(comment_form.comment) }}
+          {{ wtforms_util.render_field_div(comment_form.field_comment) }}
           <div class="form_submit_buttons">
             <input type="submit" value="Post comment!" class="button" />
           </div>
       {% if comments %}
         {% for comment in comments %}
           {% set comment_author = comment.author() %}
-          <div class="comment_wrapper" id="comment-{{ comment['_id'] }}">
+           {% if pagination.active_id == comment._id %}
+              <div class="comment_wrapper comment_active" id="comment-{{ comment['_id'] }}">
+               <a name="comment" id="comment"></a>
+            {% else %}
+              <div class="comment_wrapper" id="comment-{{ comment['_id'] }}">
+           {% endif %}
             <div class="comment_content">
               {% autoescape False %}
                 {{ comment.content_html }}
               {{ comment_author['username'] }}</a> at 
             <!--</div>
             <div class="comment_datetime">-->
-              <a href="#comment-{{ comment['_id'] }}">
+              <a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment',
+                      comment = comment['_id'],
+                      user = media.uploader().username,
+                      media = media._id) }}#comment">
                 {{ "%4d-%02d-%02d %02d:%02d"|format(comment.created.year,
                                          comment.created.month,
                                          comment.created.day,
           </div>
         {% endfor %}
 
-        {{ render_pagination(request, pagination) }}
+        {{ render_pagination(request, pagination, 
+             request.urlgen('mediagoblin.user_pages.media_home',
+             user = media.uploader().username,
+             media = media._id)) }}
       </div>
     {% endif %}
     <div class="grid_5 omega">
index 9f7d2fbdf4f2a35486df948daf99645d31e17a00..b234d73918a023cd89b05c994625e76a82c8a473 100644 (file)
@@ -17,5 +17,5 @@
 import wtforms\r
 \r
 class MediaCommentForm(wtforms.Form):\r
-       comment = wtforms.TextAreaField('Comment',\r
-       [wtforms.validators.Required()])
\ No newline at end of file
+       field_comment = wtforms.TextAreaField('Comment',\r
+       [wtforms.validators.Required()])\r
index 255b6f668fe2ad6cadc0e7f301c333270ba0b8d5..3be0617dd74e69ef99fd89e60e3a7295b65d8814 100644 (file)
@@ -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/',
index 3a8684d38f59d44baa59b02db4538c4b01078c9d..ca1060a30955c1c7ba5c12ffeff8365f2305c8cd 100644 (file)
@@ -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'])
 
index ab219df034e9c0d0ee0c36e8330d3512fa94108f..7b1e4a2a7c36535aeb6a484965b8b338cf31ab9e 100644 (file)
@@ -14,6 +14,8 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+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):
         """