# -*- coding: utf-8 -*-
# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
#
# This file is part of HyperKitty.
#
# HyperKitty is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# HyperKitty 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 General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# HyperKitty. If not, see .
#
# Author: Aamir Khan
# Author: Aurelien Bompard
#
import datetime
from collections import namedtuple, defaultdict
import django.utils.simplejson as json
from django.shortcuts import redirect, render
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils import formats
from django.utils.dateformat import format as date_format
from django.utils.timezone import utc
from django.http import Http404, HttpResponse
from hyperkitty.models import Tag, Favorite
from hyperkitty.lib import get_store
from hyperkitty.lib.view_helpers import FLASH_MESSAGES, \
get_category_widget, get_months, get_display_dates, daterange, \
is_thread_unread, get_recent_list_activity
from hyperkitty.lib.paginator import paginate
from hyperkitty.lib.voting import set_message_votes, set_thread_votes
from hyperkitty.lib.mailman import check_mlist_private
if settings.USE_MOCKUPS:
from hyperkitty.lib.mockup import generate_top_author, generate_thread_per_category
@check_mlist_private
def archives(request, mlist_fqdn, year=None, month=None, day=None):
if year is None and month is None:
today = datetime.date.today()
return redirect(reverse(
'archives_with_month', kwargs={
"mlist_fqdn": mlist_fqdn,
'year': today.year,
'month': today.month}))
begin_date, end_date = get_display_dates(year, month, day)
store = get_store(request)
mlist = store.get_list(mlist_fqdn)
threads = store.get_threads(mlist_fqdn, start=begin_date, end=end_date)
if day is None:
list_title = date_format(begin_date, "F Y")
no_results_text = "for this month"
else:
#list_title = date_format(begin_date, settings.DATE_FORMAT)
list_title = formats.date_format(begin_date) # works with i18n
no_results_text = "for this day"
extra_context = {
'month': begin_date,
'month_num': begin_date.month,
"list_title": list_title.capitalize(),
"no_results_text": no_results_text,
}
if day is None:
month_activity = mlist.get_month_activity(int(year), int(month))
extra_context["participants"] = month_activity.participants_count
return _thread_list(request, mlist, threads, extra_context=extra_context)
def _thread_list(request, mlist, threads, template_name='thread_list.html', extra_context={}):
if mlist is None:
raise Http404("No archived mailing-list by that name.")
store = get_store(request)
threads = paginate(threads, request.GET.get('page'))
participants = set()
for thread in threads:
if "participants" not in extra_context:
participants.update(thread.participants)
# Votes
set_thread_votes(thread)
# Favorites
thread.favorite = False
if request.user.is_authenticated():
try:
Favorite.objects.get(list_address=mlist.name,
threadid=thread.thread_id,
user=request.user)
except Favorite.DoesNotExist:
pass
else:
thread.favorite = True
# Tags
try:
thread.tags = Tag.objects.filter(threadid=thread.thread_id,
list_address=mlist.name)
except Tag.DoesNotExist:
thread.tags = []
# Category
thread.category_hk, thread.category_form = \
get_category_widget(request, thread.category)
# Unread status
thread.unread = is_thread_unread(request, mlist.name, thread)
flash_messages = []
flash_msg = request.GET.get("msg")
if flash_msg:
flash_msg = { "type": FLASH_MESSAGES[flash_msg][0],
"msg": FLASH_MESSAGES[flash_msg][1] }
flash_messages.append(flash_msg)
context = {
'mlist' : mlist,
'threads': threads,
'participants': len(participants),
'months_list': get_months(store, mlist.name),
'flash_messages': flash_messages,
}
context.update(extra_context)
return render(request, template_name, context)
@check_mlist_private
def overview(request, mlist_fqdn=None):
if not mlist_fqdn:
return redirect('/')
store = get_store(request)
mlist = store.get_list(mlist_fqdn)
if mlist is None:
raise Http404("No archived mailing-list by that name.")
begin_date, end_date = mlist.get_recent_dates()
threads_result = store.get_threads(
list_name=mlist.name, start=begin_date, end=end_date)
threads = []
for thread_obj in threads_result:
# Votes
set_thread_votes(thread_obj)
thread_obj.category_widget = get_category_widget(
None, thread_obj.category)[0]
thread_obj.unread = is_thread_unread(request, mlist.name, thread_obj)
threads.append(thread_obj)
# top threads are the one with the most answers
top_threads = sorted(threads, key=lambda t: len(t), reverse=True)
# active threads are the ones that have the most recent posting
active_threads = sorted(threads, key=lambda t: t.date_active, reverse=True)
# top authors are the ones that have the most kudos. How do we determine
# that? Most likes for their post?
if settings.USE_MOCKUPS:
authors = generate_top_author()
authors = sorted(authors, key=lambda author: author.kudos)
authors.reverse()
else:
authors = []
# Top posters
top_posters = []
for poster in store.get_top_participants(list_name=mlist.name,
start=begin_date, end=end_date, limit=5):
top_posters.append({"name": poster[0], "email": poster[1],
"count": poster[2]})
# Popular threads
pop_threads = sorted([ t for t in threads if t.likes - t.dislikes > 0 ],
key=lambda t: t.likes - t.dislikes,
reverse=True)
# Threads by category
threads_by_category = {}
for thread in active_threads:
if not thread.category:
continue
# don't use defaultdict, use .setdefault():
# http://stackoverflow.com/questions/4764110/django-template-cant-loop-defaultdict
if len(threads_by_category.setdefault(thread.category, [])) >= 5:
continue
threads_by_category[thread.category].append(thread)
context = {
'view_name': 'overview',
'mlist' : mlist,
'top_threads': top_threads[:5],
'most_active_threads': active_threads[:5],
'top_author': authors,
'top_posters': top_posters,
'pop_threads': pop_threads[:5],
'threads_by_category': threads_by_category,
'months_list': get_months(store, mlist.name),
}
return render(request, "overview.html", context)
@check_mlist_private
def recent_activity(request, mlist_fqdn):
store = get_store(request)
mlist = store.get_list(mlist_fqdn)
evolution = get_recent_list_activity(store, mlist)
return HttpResponse(json.dumps({"evolution": evolution}),
content_type='application/javascript')