summaryrefslogtreecommitdiffstats
path: root/hyperkitty/views/thread.py
diff options
context:
space:
mode:
authorAurélien Bompard <aurelien@bompard.org>2013-05-14 13:44:42 +0200
committerAurélien Bompard <aurelien@bompard.org>2013-05-14 13:44:42 +0200
commitfb6423fd8d2e0068c9c5b5bb8a643ea991e59739 (patch)
tree5b8e07532ca7763052017e3027eb8db8affa06e6 /hyperkitty/views/thread.py
parent4b1df7bbdb0f0fa35cf738235aff8170a37b7d04 (diff)
downloadhyperkitty-fb6423fd8d2e0068c9c5b5bb8a643ea991e59739.tar.gz
hyperkitty-fb6423fd8d2e0068c9c5b5bb8a643ea991e59739.tar.xz
hyperkitty-fb6423fd8d2e0068c9c5b5bb8a643ea991e59739.zip
Speed up page loading on long threads
Speed up page loading on threads with many replies by loading the replies asynchronously. Preserve search engine indexation by detecting bots and serving the usual page in one go.
Diffstat (limited to 'hyperkitty/views/thread.py')
-rw-r--r--hyperkitty/views/thread.py77
1 files changed, 65 insertions, 12 deletions
diff --git a/hyperkitty/views/thread.py b/hyperkitty/views/thread.py
index 7929ac6..be92be7 100644
--- a/hyperkitty/views/thread.py
+++ b/hyperkitty/views/thread.py
@@ -31,6 +31,7 @@ from django.template import RequestContext, loader
from django.shortcuts import render
from django.core.urlresolvers import reverse
from django.core.exceptions import SuspiciousOperation
+import robot_detection
from hyperkitty.models import Tag, Favorite
from forms import SearchForm, AddTagForm, ReplyForm
@@ -38,14 +39,10 @@ from hyperkitty.lib import get_months, get_store, stripped_subject
from hyperkitty.lib.voting import set_message_votes
-def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
- ''' Displays all the email for a given thread identifier '''
- search_form = SearchForm(auto_id=False)
- store = get_store(request)
- thread = store.get_thread(mlist_fqdn, threadid)
+def _get_thread_replies(request, thread):
+ '''Get and sort the replies for a thread'''
if not thread:
raise Http404
- prev_thread, next_thread = store.get_thread_neighbors(mlist_fqdn, threadid)
if "sort" in request.GET and request.GET["sort"] == "date":
sort_mode = "date"
@@ -54,7 +51,10 @@ def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
sort_mode = "thread"
emails = thread.emails_by_reply
- participants = {}
+ # Don't forget to add the sender to the participants
+ participants = {thread.starting_email.sender_name:
+ thread.starting_email.sender_email}
+ emails = list(emails)[1:] # only select replies
for email in emails:
# Extract all the votes for this message
set_message_votes(email, request.user)
@@ -67,6 +67,21 @@ def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
if email.level > 5:
email.level = 5
+ return {"replies": emails, "participants": participants}
+
+
+def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
+ ''' Displays all the email for a given thread identifier '''
+ search_form = SearchForm(auto_id=False)
+ store = get_store(request)
+ thread = store.get_thread(mlist_fqdn, threadid)
+ if not thread:
+ raise Http404
+ prev_thread, next_thread = store.get_thread_neighbors(mlist_fqdn, threadid)
+
+ sort_mode = request.GET.get("sort", "thread")
+ set_message_votes(thread.starting_email, request.user)
+
from_url = reverse("thread", kwargs={"mlist_fqdn":mlist_fqdn,
"threadid":threadid})
# Tags
@@ -95,17 +110,22 @@ def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
mlist = store.get_list(mlist_fqdn)
subject = stripped_subject(mlist, thread.starting_email.subject)
+ # TODO: eventually move to a middleware ?
+ # http://djangosnippets.org/snippets/1865/
+ is_bot = True
+ user_agent = request.META.get('HTTP_USER_AGENT', None)
+ if user_agent:
+ is_bot = robot_detection.is_robot(user_agent)
+
context = {
- 'mlist' : mlist,
- 'threadid' : threadid,
+ 'mlist': mlist,
+ 'threadid': threadid,
'subject': subject,
- 'tags' : tags,
+ 'tags': tags,
'search_form': search_form,
'addtag_form': tag_form,
'month': thread.date_active,
- 'participants': participants,
'first_mail': thread.starting_email,
- 'replies': list(emails)[1:],
'neighbors': (prev_thread, next_thread),
'months_list': get_months(store, mlist.name),
'days_inactive': days_inactive.days,
@@ -113,10 +133,43 @@ def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
'sort_mode': sort_mode,
'fav_action': fav_action,
'reply_form': ReplyForm(),
+ 'is_bot': is_bot,
}
+
+ if is_bot:
+ # Don't rely on AJAX to load the replies
+ thread_replies = _get_thread_replies(request, thread)
+ context["participants"] = thread_replies["participants"]
+ context["replies"] = thread_replies["replies"]
+
return render(request, "thread.html", context)
+def replies(request, mlist_fqdn, threadid):
+ """Get JSON encoded lists with the replies and the participants"""
+ store = get_store(request)
+ thread = store.get_thread(mlist_fqdn, threadid)
+ thread_replies = _get_thread_replies(request, thread)
+ mlist = store.get_list(mlist_fqdn)
+ context = {
+ 'mlist': mlist,
+ 'threadid': threadid,
+ 'reply_form': ReplyForm(),
+ }
+ context["participants"] = thread_replies["participants"]
+ context["replies"] = thread_replies["replies"]
+
+ replies_tpl = loader.get_template('threads/replies.html')
+ replies_html = replies_tpl.render(RequestContext(request, context))
+ participants_tpl = loader.get_template('threads/participants.html')
+ participants_html = participants_tpl.render(RequestContext(request, context))
+ response = {"replies_html": replies_html,
+ "participants_html": participants_html,
+ }
+ return HttpResponse(json.dumps(response),
+ mimetype='application/javascript')
+
+
def add_tag(request, mlist_fqdn, threadid):
""" Add a tag to a given thread. """
if not request.user.is_authenticated():