diff options
Diffstat (limited to 'hyperkitty')
-rw-r--r-- | hyperkitty/lib/compat.py | 53 | ||||
-rw-r--r-- | hyperkitty/static/css/style.css | 3 | ||||
-rw-r--r-- | hyperkitty/urls.py | 16 | ||||
-rw-r--r-- | hyperkitty/views/compat.py | 112 |
4 files changed, 179 insertions, 5 deletions
diff --git a/hyperkitty/lib/compat.py b/hyperkitty/lib/compat.py new file mode 100644 index 0000000..cb0a864 --- /dev/null +++ b/hyperkitty/lib/compat.py @@ -0,0 +1,53 @@ +#-*- 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 <http://www.gnu.org/licenses/>. +# + +import re +import datetime + +PORT_IN_URL = re.compile(':\d+$') + + +def get_list_by_name(list_name, store, request): + arch_list_names = store.get_list_names() + matching = [] + for name in arch_list_names: + if name[:name.index("@")] == list_name: + matching.append(name) + + if len(matching) == 0: # no candidate found + return None + if len(matching) == 1: # only one candidate + return store.get_list(matching[0]) + + # more than one result, try using the hostname + domain = request.get_host() + domain = PORT_IN_URL.sub('', domain) + list_fqdn = "%s@%s" % (list_name, domain) + if list_fqdn in matching: + return store.get_list(list_fqdn) + + # return the first match, arbitrarily + return store.get_list(matching[0]) + +def month_name_to_num(month_name): + """map month names to months numbers""" + today = datetime.date.today() + months = dict( (today.replace(month=num).strftime('%B'), num) + for num in range(1, 12) ) + return months[month_name] diff --git a/hyperkitty/static/css/style.css b/hyperkitty/static/css/style.css index ae32605..9c8e73c 100644 --- a/hyperkitty/static/css/style.css +++ b/hyperkitty/static/css/style.css @@ -408,7 +408,8 @@ li.attachments a.attachments { li.attachments ul { position: absolute; background-color: #F6F6F6; - margin-left: 0; + padding-left: 20px; + margin-left: 1em; } li.attachments ul li { list-style-position: inside; diff --git a/hyperkitty/urls.py b/hyperkitty/urls.py index bc52699..ab2719e 100644 --- a/hyperkitty/urls.py +++ b/hyperkitty/urls.py @@ -57,7 +57,6 @@ urlpatterns = patterns('hyperkitty.views', ### MESSAGE LEVEL VIEWS ### - # Vote a message url(r'^message/(?P<mlist_fqdn>.*@.*)/(?P<hashid>\w+)/$', 'message.index', name='message_index'), @@ -68,7 +67,7 @@ urlpatterns = patterns('hyperkitty.views', 'message.vote', name='message_vote'), ### MESSAGE LEVEL VIEW ENDS ### - + ### THREAD LEVEL VIEWS ### # Thread view page @@ -80,7 +79,7 @@ urlpatterns = patterns('hyperkitty.views', 'thread.add_tag', name='add_tag'), ### THREAD LEVEL VIEW ENDS ### - + # REST API url(r'^api/$', 'api.api'), url(r'^api/email\/(?P<mlist_fqdn>.*@.*)\/(?P<hashid>.*)/', @@ -93,7 +92,7 @@ urlpatterns = patterns('hyperkitty.views', # Uncomment the admin/doc line below to enable admin documentation: # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - # Admin + # Admin url(r'^admin/', include(admin.site.urls)), # Robots.txt @@ -103,6 +102,15 @@ urlpatterns = patterns('hyperkitty.views', # Social Auth url(r'', include('social_auth.urls')), + # Mailman 2.X compatibility + url(r'^listinfo/?$', 'compat.summary'), + url(r'^listinfo/(?P<list_name>[^/]+)/?$', 'compat.summary'), + url(r'^pipermail/(?P<list_name>[^/]+)/?$', 'compat.summary'), + url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)/?$', 'compat.arch_month'), + url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)/(?P<summary_type>[a-z]+)\.html$', 'compat.arch_month'), + url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)\.txt.gz', 'compat.arch_month_mbox'), + url(r'^pipermail/(?P<list_name>[^/]+)/(?P<year>\d\d\d\d)-(?P<month_name>\w+)/(?P<msg_num>\d+)\.html$', 'compat.message'), + ) #) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += staticfiles_urlpatterns() diff --git a/hyperkitty/views/compat.py b/hyperkitty/views/compat.py new file mode 100644 index 0000000..dea2174 --- /dev/null +++ b/hyperkitty/views/compat.py @@ -0,0 +1,112 @@ +# -*- 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 <http://www.gnu.org/licenses/>. +# + +from __future__ import with_statement + +import os +import mailbox +import datetime +import tempfile +import gzip +from cStringIO import StringIO + +from django.core.urlresolvers import reverse +from django.http import HttpResponse, HttpResponseRedirect, Http404 + +from hyperkitty.lib import get_store +from hyperkitty.lib.compat import get_list_by_name, month_name_to_num + + +def summary(request, list_name=None): + if list_name is None: + return HttpResponseRedirect(reverse('root')) + store = get_store(request) + mlist = get_list_by_name(list_name, store, request) + if mlist is None: + raise Http404("No archived mailing-list by that name.") + url = reverse('list_overview', kwargs={'mlist_fqdn': mlist.name}) + #return HttpResponse(request.build_absolute_uri(url)) + return HttpResponseRedirect(url) + + +def arch_month(request, list_name, year, month_name, summary_type="thread"): + store = get_store(request) + mlist = get_list_by_name(list_name, store, request) + if mlist is None: + raise Http404("No archived mailing-list by that name.") + url = reverse('archives_with_month', kwargs={ + 'mlist_fqdn': mlist.name, + 'year': year, + 'month': str(month_name_to_num(month_name)).rjust(2, "0"), + }) + #return HttpResponse(request.build_absolute_uri(url)) + return HttpResponseRedirect(url) + + +def arch_month_mbox(request, list_name, year, month_name): + store = get_store(request) + mlist = get_list_by_name(list_name, store, request) + if mlist is None: + raise Http404("No archived mailing-list by that name.") + month = month_name_to_num(month_name) + year = int(year) + begin_date = datetime.datetime(year, month, 1) + if month != 12: + end_month = month + 1 + else: + end_month = 1 + end_date = datetime.datetime(year, end_month, 1) + messages = store.get_messages(mlist.name, start=begin_date, end=end_date) + messages.reverse() # they are sorted recent first by default + mboxfile, mboxfilepath = tempfile.mkstemp(prefix="hyperkitty-", + suffix=".mbox.gz") + os.close(mboxfile) + mbox = mailbox.mbox(mboxfilepath) + for message in messages: + mbox.add(message.full) + mbox.close() + content = StringIO() + zipped_content = gzip.GzipFile(fileobj=content) + with gzip.GzipFile(fileobj=content, mode="wb") as zipped_content: + with open(mboxfilepath, "rb") as mboxfile: + zipped_content.write(mboxfile.read()) + response = HttpResponse(content.getvalue()) + content.close() + response['Content-Type'] = "application/mbox+gz" + response['Content-Disposition'] = 'attachment; filename=%d-%s.txt.gz' \ + % (year, month_name) + response['Content-Length'] = len(response.content) + os.remove(mboxfilepath) + return response + + +def message(request, list_name, year, month_name, msg_num): + store = get_store(request) + mlist = get_list_by_name(list_name, store, request) + if mlist is None: + raise Http404("No archived mailing-list by that name.") + message = store.get_message_by_number(mlist.name, int(msg_num)) + if message is None: + raise Http404("No such message in this mailing-list.") + url = reverse('message_index', kwargs={ + 'mlist_fqdn': mlist.name, + 'hashid': message.message_id_hash, + }) + #return HttpResponse(request.build_absolute_uri(url)) + return HttpResponseRedirect(url) |