summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hyperkitty/lib/__init__.py21
-rw-r--r--hyperkitty/static/css/style.css4
-rw-r--r--hyperkitty/templates/thread.html13
-rw-r--r--hyperkitty/templatetags/hk_generic.py9
-rw-r--r--hyperkitty/views/thread.py47
-rw-r--r--requirements.txt1
6 files changed, 75 insertions, 20 deletions
diff --git a/hyperkitty/lib/__init__.py b/hyperkitty/lib/__init__.py
index 52b6bdc..14bde15 100644
--- a/hyperkitty/lib/__init__.py
+++ b/hyperkitty/lib/__init__.py
@@ -23,6 +23,7 @@ import urllib
from hashlib import md5
import datetime
+import networkx as nx
from django.conf import settings
@@ -86,3 +87,23 @@ def get_display_dates(year, month, day):
end_date = begin_date + datetime.timedelta(days=1)
return begin_date, end_date
+
+
+def sort_thread(thread):
+ def walk_successors(msgid, level, result):
+ obj = graph.node[msgid]["obj"]
+ obj.level = level
+ result.append(obj)
+ level += 1
+ for succ in sorted(graph.successors(msgid),
+ key=lambda m: graph.node[m]["num"]):
+ walk_successors(succ, level, result)
+ level -= 1
+ graph = nx.DiGraph()
+ for index, email in enumerate(thread.emails):
+ graph.add_node(email.message_id, num=index, obj=email)
+ if email.in_reply_to is not None:
+ graph.add_edge(email.in_reply_to, email.message_id)
+ result = []
+ walk_successors(thread.starting_email.message_id, 0, result)
+ return result
diff --git a/hyperkitty/static/css/style.css b/hyperkitty/static/css/style.css
index 9ac592a..68f13e2 100644
--- a/hyperkitty/static/css/style.css
+++ b/hyperkitty/static/css/style.css
@@ -651,6 +651,10 @@ ul.attachments-list li {
float: right;
}
+.sort-mode {
+ text-align: right;
+}
+
/* The email thread */
.even, .odd {
border-top: 1px solid rgb(179, 179, 179);
diff --git a/hyperkitty/templates/thread.html b/hyperkitty/templates/thread.html
index 8ea45d2..add1fba 100644
--- a/hyperkitty/templates/thread.html
+++ b/hyperkitty/templates/thread.html
@@ -26,8 +26,19 @@
{% include 'messages/first_email.html' %}
<!-- End first email -->
+ <p class="sort-mode">
+ {% if sort_mode == "date" %}
+ <a href="{% url thread threadid=threadid, mlist_fqdn=list_address %}?sort=thread"
+ >Show replies by thread</a>
+ {% else %}
+ <a href="{% url thread threadid=threadid, mlist_fqdn=list_address %}?sort=date"
+ >Show replies by date</a>
+ {% endif %}
+ </p>
+
{% for email in replies %}
- <div class="{% cycle 'even' 'odd' %}">
+ <div class="{% cycle 'even' 'odd' %}"
+ {% if email.level %}style="margin-left:{{ email.level|multiply:"2" }}em;"{% endif %}>
<!-- Start email -->
{% include 'messages/message.html' %}
<!-- End of email -->
diff --git a/hyperkitty/templatetags/hk_generic.py b/hyperkitty/templatetags/hk_generic.py
index 555246f..390c51c 100644
--- a/hyperkitty/templatetags/hk_generic.py
+++ b/hyperkitty/templatetags/hk_generic.py
@@ -171,3 +171,12 @@ def snip_quoted(content, quotemsg="[...]", autoescape=None):
+' </div>')
content = content.replace("\n".join(quote_orig), replaced)
return mark_safe(content)
+
+
+@register.filter()
+def multiply(num1, num2):
+ if int(num2) == float(num2):
+ num2 = int(num2)
+ else:
+ num2 = float(num2)
+ return num1 * num2
diff --git a/hyperkitty/views/thread.py b/hyperkitty/views/thread.py
index afe389b..f0c959f 100644
--- a/hyperkitty/views/thread.py
+++ b/hyperkitty/views/thread.py
@@ -37,7 +37,7 @@ from django.contrib.auth.decorators import (login_required,
from hyperkitty.models import Rating, Tag
#from hyperkitty.lib.mockup import *
from forms import *
-from hyperkitty.lib import get_months, get_store, stripped_subject
+from hyperkitty.lib import get_months, get_store, stripped_subject, sort_thread
def thread_index(request, mlist_fqdn, threadid):
@@ -50,13 +50,18 @@ def thread_index(request, mlist_fqdn, threadid):
raise Http404
prev_thread, next_thread = store.get_thread_neighbors(mlist_fqdn, threadid)
- participants = {}
- cnt = 0
+ if "sort" in request.GET and request.GET["sort"] == "date":
+ sort_mode = "date"
+ emails = thread.emails
+ else:
+ sort_mode = "thread"
+ emails = sort_thread(thread)
- for message in thread.emails:
+ participants = {}
+ for email in emails:
# Extract all the votes for this message
try:
- votes = Rating.objects.filter(messageid=message.message_id)
+ votes = Rating.objects.filter(messageid=email.message_id)
except Rating.DoesNotExist:
votes = {}
@@ -71,21 +76,25 @@ def thread_index(request, mlist_fqdn, threadid):
else:
pass
- message.votes = votes
- message.likes = likes
- message.dislikes = dislikes
- message.likestatus = "neutral"
- if message.likes - message.dislikes >= 10:
- message.likestatus = "likealot"
- elif message.likes - message.dislikes > 0:
- message.likestatus = "like"
- #elif message.likes - message.dislikes < 0:
- # message.likestatus = "dislike"
+ email.votes = votes
+ email.likes = likes
+ email.dislikes = dislikes
+ email.likestatus = "neutral"
+ if email.likes - email.dislikes >= 10:
+ email.likestatus = "likealot"
+ elif email.likes - email.dislikes > 0:
+ email.likestatus = "like"
+ #elif email.likes - email.dislikes < 0:
+ # email.likestatus = "dislike"
# Statistics on how many participants and messages this month
- participants[message.sender_name] = message.sender_email
- cnt = cnt + 1
+ participants[email.sender_name] = email.sender_email
+
+ if sort_mode == "thread":
+ email.level -= 1 # replies start ragged left
+ if email.level > 5:
+ email.level = 5
archives_length = get_months(store, mlist_fqdn)
from_url = reverse("thread", kwargs={"mlist_fqdn":mlist_fqdn,
@@ -115,14 +124,14 @@ def thread_index(request, mlist_fqdn, threadid):
'addtag_form': tag_form,
'month': 'Thread',
'participants': participants,
- 'answers': cnt,
'first_mail': thread.starting_email,
- 'replies': list(thread.emails)[1:],
+ 'replies': list(emails)[1:],
'neighbors': (prev_thread, next_thread),
'archives_length': archives_length,
'days_inactive': days_inactive.days,
'days_old': days_old.days,
'use_mockups': settings.USE_MOCKUPS,
+ 'sort_mode': sort_mode,
})
return HttpResponse(t.render(c))
diff --git a/requirements.txt b/requirements.txt
index 77cc578..9fd8461 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,4 @@ django-social-auth>=0.7.1
djangorestframework>=2.0.0
mailman>=3.0.0b2
kittystore
+networkx