various fixes
This commit is contained in:
parent
cc957f3de5
commit
a9860d82ba
@ -13,10 +13,10 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='Attachment',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('filehash', models.CharField(editable=False, max_length=256)),
|
||||
('filename', models.CharField(max_length=256)),
|
||||
('mimetype', models.CharField(max_length=256, default='text/plain')),
|
||||
('mimetype', models.CharField(default='text/plain', max_length=256)),
|
||||
('width', models.IntegerField(default=0)),
|
||||
('height', models.IntegerField(default=0)),
|
||||
('banned', models.BooleanField(default=False)),
|
||||
@ -25,7 +25,7 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='Newsgroup',
|
||||
fields=[
|
||||
('name', models.CharField(editable=False, max_length=256, serialize=False, primary_key=True)),
|
||||
('name', models.CharField(primary_key=True, serialize=False, editable=False, max_length=256)),
|
||||
('posts_per_page', models.IntegerField(default=10)),
|
||||
('max_pages', models.IntegerField(default=10)),
|
||||
('banned', models.BooleanField(default=False)),
|
||||
@ -34,16 +34,17 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='Post',
|
||||
fields=[
|
||||
('msgid', models.CharField(editable=False, max_length=256, serialize=False, primary_key=True)),
|
||||
('msgid', models.CharField(primary_key=True, serialize=False, editable=False, max_length=256)),
|
||||
('posthash', models.CharField(editable=False, max_length=256)),
|
||||
('reference', models.CharField(max_length=256, default='')),
|
||||
('reference', models.CharField(default='', max_length=256)),
|
||||
('message', models.TextField(default='')),
|
||||
('subject', models.CharField(max_length=256, default='None')),
|
||||
('name', models.CharField(max_length=256, default='Anonymous')),
|
||||
('pubkey', models.CharField(max_length=64, default='')),
|
||||
('signature', models.CharField(max_length=64, default='')),
|
||||
('posted', models.DateTimeField()),
|
||||
('subject', models.CharField(default='None', max_length=256)),
|
||||
('name', models.CharField(default='Anonymous', max_length=256)),
|
||||
('pubkey', models.CharField(default='', max_length=64)),
|
||||
('signature', models.CharField(default='', max_length=64)),
|
||||
('posted', models.IntegerField(default=0)),
|
||||
('placeholder', models.BooleanField(default=False)),
|
||||
('last_bumped', models.IntegerField(default=0)),
|
||||
('attachments', models.ManyToManyField(to='frontend.Attachment')),
|
||||
('newsgroup', models.ForeignKey(to='frontend.Newsgroup')),
|
||||
],
|
||||
|
@ -1,8 +1,11 @@
|
||||
from django.db import models
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from . import util
|
||||
|
||||
import mimetypes
|
||||
from datetime import datetime
|
||||
|
||||
class Attachment(models.Model):
|
||||
"""
|
||||
@ -37,12 +40,11 @@ class Newsgroup(models.Model):
|
||||
banned = models.BooleanField(default=False)
|
||||
|
||||
def get_absolute_url(self):
|
||||
from django.urls import reverse
|
||||
return reverse('nntpchan.frontend.views.boardpage', args=[self.name, '0'])
|
||||
return reverse('board', args=[self.name[9:]])
|
||||
|
||||
class Post(models.Model):
|
||||
"""
|
||||
a post made
|
||||
a post made anywhere on the boards
|
||||
"""
|
||||
|
||||
msgid = models.CharField(max_length=256, primary_key=True, editable=False)
|
||||
@ -55,8 +57,9 @@ class Post(models.Model):
|
||||
signature = models.CharField(max_length=64, default='')
|
||||
newsgroup = models.ForeignKey(Newsgroup, on_delete=models.CASCADE)
|
||||
attachments = models.ManyToManyField(Attachment)
|
||||
posted = models.DateTimeField()
|
||||
posted = models.IntegerField(default=0)
|
||||
placeholder = models.BooleanField(default=False)
|
||||
last_bumped = models.IntegerField(default=0)
|
||||
|
||||
def get_all_replies(self):
|
||||
if self.is_op():
|
||||
@ -70,16 +73,23 @@ class Post(models.Model):
|
||||
return rpls
|
||||
|
||||
def is_op(self):
|
||||
return self.reference == ''
|
||||
return self.reference == '' or self.reference == self.msgid
|
||||
|
||||
def shorthash(self):
|
||||
return self.posthash[:10]
|
||||
|
||||
def postdate(self):
|
||||
return datetime.fromtimestamp(self.posted)
|
||||
|
||||
def get_absolute_url(self):
|
||||
if self.is_op():
|
||||
op = util.hashid(self.msgid)
|
||||
return '/t/{}/'.format(op)
|
||||
return reverse('thread', args=[op])
|
||||
else:
|
||||
op = util.hashid(self.reference)
|
||||
frag = util.hashid(self.msgid)
|
||||
return '/t/{}/#{}'.format(op, frag)
|
||||
return reverse('thread', args=[op]) + '#{}'.format(frag)
|
||||
|
||||
def bump(self):
|
||||
if self.is_op():
|
||||
self.last_bumped = util.time_int(datetime.now())
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 135 B |
@ -1,6 +1,6 @@
|
||||
|
||||
body, html {
|
||||
background-color: #eef2ff;
|
||||
background: #EEF2FF url('/static/bg.png') repeat-x 50% 0%;
|
||||
}
|
||||
|
||||
div {
|
||||
@ -68,6 +68,27 @@ img.thumb {
|
||||
color: #480188;
|
||||
}
|
||||
|
||||
.frontpage.posts {
|
||||
width: 50%;
|
||||
padding-top: 10%;
|
||||
padding-left: 25%;
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 8pt;
|
||||
margin-top: 5%;
|
||||
maring-bottom: 5%;
|
||||
padding-left: 1%;
|
||||
margin: 0px;
|
||||
min-width: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.paginator {
|
||||
padding-top: 5%;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
|
||||
.cite {
|
||||
float: right;
|
||||
}
|
||||
|
@ -143,3 +143,10 @@ def memepost(text, autoescape=True):
|
||||
|
||||
return mark_safe(doFilter(line_funcs, return_text, conditional_escape))
|
||||
|
||||
|
||||
@register.filter(name='truncate')
|
||||
@stringfilter
|
||||
def truncate(text, truncate=500):
|
||||
if len(text) > truncate:
|
||||
return text[:truncate] + '...'
|
||||
return text
|
||||
|
@ -2,6 +2,8 @@ import base64
|
||||
import hashlib
|
||||
import re
|
||||
|
||||
import time
|
||||
|
||||
def hashid(msgid):
|
||||
h = hashlib.sha1()
|
||||
m = '{}'.format(msgid).encode('ascii')
|
||||
@ -19,8 +21,6 @@ def hashfile(data):
|
||||
def msgid_valid(msgid):
|
||||
return re.match("<[a-zA-Z0-9\$\._\-\|]+@[a-zA-Z0-9\$\._\-\|]+>$", msgid) is not None
|
||||
|
||||
def save_part(part):
|
||||
"""
|
||||
save a mime part to disk
|
||||
"""
|
||||
def time_int(dtime):
|
||||
return time.mktime(dtime.timetuple())
|
||||
|
||||
|
@ -19,8 +19,26 @@ class BoardView(generic.View):
|
||||
else:
|
||||
begin = page * group.posts_per_page
|
||||
end = begin + group.posts_per_page
|
||||
posts = self.model.objects.filter(newsgroup=group, reference='').order_by('-posted')[begin:end]
|
||||
return render(request, self.template_name, {'threads': posts, 'page': page, 'name': newsgroup})
|
||||
print(begin, end)
|
||||
posts = self.model.objects.filter(newsgroup=group).order_by('-posted')[begin:end]
|
||||
roots = []
|
||||
for post in posts:
|
||||
if post.is_op():
|
||||
if post not in roots:
|
||||
roots.append(post)
|
||||
else:
|
||||
op = self.model.objects.filter(msgid=post.reference)
|
||||
if len(op) > 0:
|
||||
op = op[0]
|
||||
if op not in roots:
|
||||
roots.append(op)
|
||||
|
||||
ctx = {'threads': roots,'page': page, 'name': newsgroup}
|
||||
if page < group.max_pages:
|
||||
ctx['nextpage'] = '/{}/{}/'.format(group.name, page + 1)
|
||||
if page > 0:
|
||||
ctx['prevpage'] = '/{}/{}/'.format(group.name, page - 1)
|
||||
return render(request, self.template_name, ctx)
|
||||
|
||||
|
||||
class ThreadView(generic.ListView):
|
||||
@ -33,12 +51,16 @@ class ThreadView(generic.ListView):
|
||||
|
||||
|
||||
|
||||
class FrontPageView(generic.ListView):
|
||||
class FrontPageView(generic.View):
|
||||
template_name = 'frontend/frontpage.html'
|
||||
model = Post
|
||||
|
||||
def get_queryset(self):
|
||||
return self.model.objects.order_by('posted')[:10]
|
||||
def get(self, request, truncate=5):
|
||||
if truncate <= 0:
|
||||
truncate = 5
|
||||
posts = self.model.objects.order_by('-posted')[:truncate]
|
||||
ctx = {'posts' : posts}
|
||||
return render(request, self.template_name, ctx)
|
||||
|
||||
|
||||
def modlog(request, page):
|
||||
|
@ -111,6 +111,8 @@ LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
DATE_FORMAT = "r"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
@ -10,7 +10,8 @@
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div id="navbar">
|
||||
<span id="navbar_title">{% block navbar_title %}nntpchan{% endblock %}</span> |
|
||||
<span id="navbar_frontpage"><a href="/">nntpchan</a></span> |
|
||||
<span id="navbar_title">{% block navbar_title %}{% endblock %}</span> |
|
||||
<span id="navbar_links">{% block navbar_links %}{% endblock %}</span> |
|
||||
<span id="navbar_left">{% block navbar_left %}| <a href="#" onclick="nntpchan_toggle_settings()">settings</a>{% endblock %}</span>
|
||||
</div>
|
||||
@ -19,9 +20,13 @@
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<center>
|
||||
<footer>
|
||||
<p> legal notice goes here </p>
|
||||
<p>All posts on this site are the responsibility of the individual poster and not the administration, pursuant to 47 U.S.C. § 230.</p>
|
||||
<p>To make a DMCA request or report illegal content, please contact the administration</p>
|
||||
</footer>
|
||||
</center>
|
||||
<script>
|
||||
ready();
|
||||
</script>
|
||||
|
@ -2,6 +2,15 @@
|
||||
{% extends "frontend/base.html" %}
|
||||
{% load chanup %}
|
||||
{% block title %} {{name}} page {{page}} {% endblock %}
|
||||
{% block navbar_links %}
|
||||
{% if prevpage %}
|
||||
<span class="navbar_link"><a href="{{prevpage}}">previous page</a></span>
|
||||
{% endif %}
|
||||
{% if nextpage %}
|
||||
{% if prevpage %}|{% endif %}
|
||||
<span class="navbar_link"><a href="{{nextpage}}">next page</a></span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<hr />
|
||||
{% for op in threads %}
|
||||
@ -9,8 +18,7 @@
|
||||
<div class="post op">
|
||||
<div class="header">
|
||||
<span class="name">{{op.name}}</span> <span class="subject">{{op.subject}}</span>
|
||||
<span class="msgid">{{op.msgid}}</span>
|
||||
<span class="posted">{{op.posted}}</span>
|
||||
<span class="posted">{{op.postdate|date}}</span>
|
||||
<span class="cite"><a href="{{op.get_absolute_url}}">>>{{op.shorthash}}</a></span>
|
||||
</div>
|
||||
|
||||
@ -19,14 +27,13 @@
|
||||
<a href="{{a.source}}"><img class="thumb" src="{{a.thumb}}"></img></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<pre class="postbody">{{op.message|memepost}}</pre>
|
||||
<pre class="postbody">{{op.message|truncate|memepost}}</pre>
|
||||
</div>
|
||||
{% for reply in op.get_board_replies %}
|
||||
<div class="post reply">
|
||||
<div class="post reply" id="{{reply.posthash}}">
|
||||
<div class="header">
|
||||
<span class="name">{{reply.name}}</span> <span class="subject">{{reply.subject}}</span>
|
||||
<span class="msgid">{{reply.msgid}}</span>
|
||||
<span class="posted">{{reply.posted}}</span>
|
||||
<span class="posted">{{reply.postdate|date}}</span>
|
||||
<span class="cite"><a href="{{reply.get_absolute_url}}">>>{{reply.shorthash}}</a></span>
|
||||
</div>
|
||||
<div class="attachments">
|
||||
@ -34,10 +41,18 @@
|
||||
<a href="{{a.source}}"><img class="thumb" src="{{a.thumb}}"></img></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<pre class="postbody">{{reply.message|memepost}}</pre>
|
||||
<pre class="postbody">{{reply.message|truncate|memepost}}</pre>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<hr />
|
||||
{% endfor %}
|
||||
|
||||
<div class="paginator">
|
||||
{% if prevpage %}
|
||||
<span class="paginator_item"><a href="{{prevpage}}">prev</a></span>
|
||||
{% endif %}
|
||||
{% if nextpage %}
|
||||
<span class="paginator_item"><a href="{{nextpage}}">next</a></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1 +1,24 @@
|
||||
{% extends "frontend/base.html" %}
|
||||
{% load chanup %}
|
||||
{% block content %}
|
||||
<div class="frontpage posts">
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<div class="header">
|
||||
<span class="boardname"><a href="{{post.newsgroup.get_absolute_url}}">{{post.newsgroup.name}}</a></span>
|
||||
</div>
|
||||
<div class="header">
|
||||
<span class="name">{{post.name}}</span> <span class="subject">{{post.subject}}</span>
|
||||
<span class="posted">{{post.postdate|date}}</span>
|
||||
<span class="cite"><a href="{{post.get_absolute_url}}">>>{{post.shorthash}}</a></span>
|
||||
</div>
|
||||
<div class="attachments">
|
||||
{% for a in post.attachments.all %}
|
||||
<a href="{{a.source}}"><img class="thumb" src="{{a.thumb}}"></img></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<pre class="postbody">{{post.message | truncate | memepost }}</pre>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,13 +1,16 @@
|
||||
{% extends "frontend/base.html" %}
|
||||
{% load chanup %}
|
||||
{% block title %} {{op.subject}} {% endblock %}
|
||||
{% block navbar_links %}
|
||||
<span class="navbar_link"><a href="{{op.newsgroup.get_absolute_url}}">back to {{op.newsgroup.name}}</a></span>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="{{op.posthash}}" class="thread">
|
||||
<div class="post op">
|
||||
<div class="header">
|
||||
<span class="name">{{op.name}}</span> <span class="subject">{{op.subject}}</span>
|
||||
<span class="msgid">{{op.msgid}}</span>
|
||||
<span class="posted">{{op.posted}}</span>
|
||||
<span class="posted">{{op.postdate|date}}</span>
|
||||
<span class="cite"><a href="{{op.get_absolute_url}}">>>{{op.shorthash}}</a></span>
|
||||
</div>
|
||||
|
||||
@ -19,11 +22,11 @@
|
||||
<pre class="postbody">{{op.message|memepost}}</pre>
|
||||
</div>
|
||||
{% for reply in op.get_all_replies %}
|
||||
<div class="post reply">
|
||||
<div class="post reply" id="{{reply.posthash}}">
|
||||
<div class="header">
|
||||
<span class="name">{{reply.name}}</span> <span class="subject">{{reply.subject}}</span>
|
||||
<span class="msgid">{{reply.msgid}}</span>
|
||||
<span class="posted">{{reply.posted}}</span>
|
||||
<span class="posted">{{reply.postdate|date}}</span>
|
||||
<span class="cite"><a href="{{reply.get_absolute_url}}">>>{{reply.shorthash}}</a></span>
|
||||
</div>
|
||||
<div class="attachments">
|
||||
|
@ -31,9 +31,10 @@ def webhook(request):
|
||||
if not util.newsgroup_valid(newsgroup):
|
||||
raise Exception("invalid newsgroup name")
|
||||
|
||||
|
||||
bump = True
|
||||
group, created = Newsgroup.objects.get_or_create(name=newsgroup)
|
||||
|
||||
if created:
|
||||
group.save()
|
||||
if group.banned:
|
||||
raise Exception("newsgroup is banned")
|
||||
|
||||
@ -42,16 +43,24 @@ def webhook(request):
|
||||
if h in msg:
|
||||
msgid = msg[h]
|
||||
break
|
||||
# check for sage
|
||||
if 'X-Sage' in msg and msg['X-Sage'] == '1':
|
||||
bump = False
|
||||
|
||||
if msgid is None:
|
||||
raise Exception("no message id specified")
|
||||
elif not util.msgid_valid(msgid):
|
||||
raise Exception("invalid message id format: {}".format(msgid))
|
||||
|
||||
opmsgid = msgid
|
||||
|
||||
h = util.hashid(msgid)
|
||||
atts = list()
|
||||
ref = msg['References'] or ''
|
||||
posted = email.utils.parsedate_to_datetime(msg['Date'])
|
||||
posted = util.time_int(email.utils.parsedate_to_datetime(msg['Date']))
|
||||
|
||||
if len(ref) > 0:
|
||||
opmsgid = ref
|
||||
|
||||
f = msg['From'] or 'anon <anon@anon>'
|
||||
name = email.utils.parseaddr(f)[0]
|
||||
@ -59,6 +68,7 @@ def webhook(request):
|
||||
'posthash': h,
|
||||
'reference': ref,
|
||||
'posted': posted,
|
||||
'last_bumped': 0,
|
||||
'name': name,
|
||||
'subject': msg["Subject"] or '',
|
||||
'newsgroup': group}, msgid=msgid)
|
||||
@ -96,6 +106,20 @@ def webhook(request):
|
||||
|
||||
for att in atts:
|
||||
post.attachments.add(att)
|
||||
|
||||
|
||||
op, _ = Post.objects.get_or_create(defaults={
|
||||
'posthash': util.hashid(opmsgid),
|
||||
'reference': '',
|
||||
'posted': 0,
|
||||
'last_bumped': 0,
|
||||
'name': 'OP',
|
||||
'subject': 'OP Not Found',
|
||||
'newsgroup': group}, msgid=opmsgid)
|
||||
if bump:
|
||||
op.bump()
|
||||
op.save()
|
||||
|
||||
except Exception as ex:
|
||||
traceback.print_exc()
|
||||
return JsonResponse({ 'error': '{}'.format(ex) })
|
||||
|
Reference in New Issue
Block a user