2010-04-21 17:44:16 +02:00
|
|
|
from __future__ import with_statement
|
2010-05-02 16:52:15 +02:00
|
|
|
import os
|
2010-05-05 17:45:12 +02:00
|
|
|
from math import ceil
|
2010-04-21 17:44:16 +02:00
|
|
|
from hashlib import md5
|
|
|
|
|
from werkzeug import parse_date
|
|
|
|
|
from jinja2.utils import urlize
|
2010-05-02 16:52:15 +02:00
|
|
|
from flask import Module, render_template, json, url_for, abort, Markup
|
2010-05-05 17:37:44 +02:00
|
|
|
from flask_website.utils import split_lines_wrapping
|
2010-05-02 19:07:42 +02:00
|
|
|
from flask_website import config
|
2010-04-21 17:44:16 +02:00
|
|
|
|
2010-05-02 19:07:42 +02:00
|
|
|
mailinglist = Module(__name__, url_prefix='/mailinglist')
|
2010-04-21 17:44:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Mail(object):
|
|
|
|
|
|
|
|
|
|
def __init__(self, d):
|
|
|
|
|
self.msgid = d['msgid']
|
|
|
|
|
self.author_name, self.author_addr = d['author']
|
|
|
|
|
self.date = parse_date(d['date'])
|
|
|
|
|
self.subject = d['subject']
|
|
|
|
|
self.children = [Mail(x) for x in d['children']]
|
|
|
|
|
self.text = d['text']
|
|
|
|
|
|
|
|
|
|
def rendered_text(self):
|
|
|
|
|
result = []
|
|
|
|
|
in_sig = False
|
2010-05-05 17:37:44 +02:00
|
|
|
for line in split_lines_wrapping(self.text):
|
2010-04-21 17:44:16 +02:00
|
|
|
if line == u'-- ':
|
2010-06-18 15:42:43 +08:00
|
|
|
in_sig = True
|
2010-06-23 11:26:45 +02:00
|
|
|
# the extra space at the end is a simple workaround for
|
|
|
|
|
# urlize not to consume the </span> as part of the URL
|
2010-04-21 17:44:16 +02:00
|
|
|
if in_sig:
|
2010-06-23 11:26:45 +02:00
|
|
|
line = Markup(u'<span class=sig>%s </span>') % line
|
2010-04-21 17:44:16 +02:00
|
|
|
elif line.startswith('>'):
|
2010-06-23 11:26:45 +02:00
|
|
|
line = Markup(u'<span class=quote>%s </span>') % line
|
2010-04-21 17:44:16 +02:00
|
|
|
result.append(urlize(line))
|
|
|
|
|
return Markup(u'\n'.join(result))
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def id(self):
|
|
|
|
|
return md5(self.msgid.encode('utf-8')).hexdigest()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Thread(object):
|
|
|
|
|
|
|
|
|
|
def __init__(self, d):
|
|
|
|
|
self.slug = d['slug'].rsplit('/', 1)[-1]
|
|
|
|
|
self.title = d['title']
|
|
|
|
|
self.reply_count = d['reply_count']
|
|
|
|
|
self.author_name, self.author_email = d['author']
|
|
|
|
|
self.date = parse_date(d['date'])
|
|
|
|
|
if 'root' in d:
|
|
|
|
|
self.root = Mail(d['root'])
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get(year, month, day, slug):
|
|
|
|
|
try:
|
2010-05-02 16:52:15 +02:00
|
|
|
with open('%s/threads/%s-%02d-%02d/%s' %
|
2010-05-02 19:07:42 +02:00
|
|
|
(config.MAILINGLIST_PATH, year, month, day, slug)) as f:
|
2010-04-21 17:44:16 +02:00
|
|
|
return Thread(json.load(f))
|
|
|
|
|
except IOError:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_list():
|
2010-05-02 19:07:42 +02:00
|
|
|
with open('%s/threads/threadlist' % config.MAILINGLIST_PATH) as f:
|
2010-04-21 17:44:16 +02:00
|
|
|
return [Thread(x) for x in json.load(f)]
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def url(self):
|
2010-05-02 16:52:15 +02:00
|
|
|
return url_for('mailinglist.show_thread', year=self.date.year,
|
2010-04-21 17:44:16 +02:00
|
|
|
month=self.date.month, day=self.date.day,
|
|
|
|
|
slug=self.slug)
|
|
|
|
|
|
|
|
|
|
|
2010-05-02 19:07:42 +02:00
|
|
|
@mailinglist.route('/')
|
2010-04-21 17:44:16 +02:00
|
|
|
def index():
|
|
|
|
|
return render_template('mailinglist/index.html')
|
|
|
|
|
|
|
|
|
|
|
2010-05-02 19:07:42 +02:00
|
|
|
@mailinglist.route('/archive/', defaults={'page': 1})
|
|
|
|
|
@mailinglist.route('/archive/page/<int:page>/')
|
2010-05-02 16:52:15 +02:00
|
|
|
def archive(page):
|
2010-04-21 17:44:16 +02:00
|
|
|
all_threads = Thread.get_list()
|
2010-05-02 19:07:42 +02:00
|
|
|
offset = (page - 1) * config.THREADS_PER_PAGE
|
|
|
|
|
threads = all_threads[offset:offset + config.THREADS_PER_PAGE]
|
2010-04-21 17:44:16 +02:00
|
|
|
if page != 1 and not threads:
|
|
|
|
|
abort(404)
|
2010-06-18 15:42:43 +08:00
|
|
|
page_count = int(ceil(len(all_threads) // float(config.THREADS_PER_PAGE)))
|
2010-05-05 17:45:12 +02:00
|
|
|
return render_template('mailinglist/archive.html',
|
2010-06-18 15:42:43 +08:00
|
|
|
page_count=page_count, page=page, threads=threads)
|
2010-04-21 17:44:16 +02:00
|
|
|
|
|
|
|
|
|
2010-05-02 19:07:42 +02:00
|
|
|
@mailinglist.route('/archive/<int:year>/<int:month>/<int:day>/<slug>/')
|
2010-05-02 16:52:15 +02:00
|
|
|
def show_thread(year, month, day, slug):
|
2010-04-21 17:44:16 +02:00
|
|
|
thread = Thread.get(year, month, day, slug)
|
|
|
|
|
if thread is None:
|
|
|
|
|
abort(404)
|
|
|
|
|
return render_template('mailinglist/show_thread.html', thread=thread)
|