more
This commit is contained in:
parent
a19d36f883
commit
8ffc8c006c
@ -2,6 +2,8 @@ from django.db import models
|
|||||||
|
|
||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
class Attachment(models.Model):
|
class Attachment(models.Model):
|
||||||
"""
|
"""
|
||||||
a file attachment assiciated with a post
|
a file attachment assiciated with a post
|
||||||
@ -13,6 +15,16 @@ class Attachment(models.Model):
|
|||||||
width = models.IntegerField(default=0)
|
width = models.IntegerField(default=0)
|
||||||
height = models.IntegerField(default=0)
|
height = models.IntegerField(default=0)
|
||||||
banned = models.BooleanField(default=False)
|
banned = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def path(self):
|
||||||
|
ext = self.filename.split('.')[-1]
|
||||||
|
return '{}{}'.format(self.filehash, ext)
|
||||||
|
|
||||||
|
def thumb(self):
|
||||||
|
return '/media/thumb-{}.jpg'.format(self.path())
|
||||||
|
|
||||||
|
def source(self):
|
||||||
|
return '/media/{}'.format(self.path())
|
||||||
|
|
||||||
|
|
||||||
class Newsgroup(models.Model):
|
class Newsgroup(models.Model):
|
||||||
@ -46,16 +58,28 @@ class Post(models.Model):
|
|||||||
posted = models.DateTimeField()
|
posted = models.DateTimeField()
|
||||||
placeholder = models.BooleanField(default=False)
|
placeholder = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def get_all_replies(self):
|
||||||
|
if self.is_op():
|
||||||
|
return Post.objects.filter(reference=self.msgid).order_by('posted')
|
||||||
|
|
||||||
|
def get_board_replies(self, truncate=5):
|
||||||
|
rpls = self.get_all_replies()
|
||||||
|
l = len(rpls)
|
||||||
|
if l > truncate:
|
||||||
|
rpls = rpls[(l+1)-truncate:l-1]
|
||||||
|
return rpls
|
||||||
|
|
||||||
def is_op(self):
|
def is_op(self):
|
||||||
return self.reference is None
|
return self.reference == ''
|
||||||
|
|
||||||
|
def shorthash(self):
|
||||||
|
return self.posthash[:10]
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
if self.is_op():
|
if self.is_op():
|
||||||
op = util.hashid(self.msgid)
|
op = util.hashid(self.msgid)
|
||||||
return reverse('nntpchan.frontend.views.threadpage', args[op])
|
return '/t/{}/'.format(op)
|
||||||
else:
|
else:
|
||||||
op = util.hashid(self.reference.msgid)
|
op = util.hashid(self.reference)
|
||||||
frag = util.hashid(self.msgid)
|
frag = util.hashid(self.msgid)
|
||||||
return reverse('nntpchan.frontend.views.threadpage', args=[op]) + '#{}'.format(frag)
|
return '/t/{}/#{}'.format(op, frag)
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
body, html {
|
||||||
|
background-color: #eef2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: sans;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar {
|
||||||
|
z-index: 20;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
margin-top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
box-shadow: 1px 10px 20px rgba(0, 0, 0, 0.15);
|
||||||
|
min-height: 20px;
|
||||||
|
background-color: #d6daf0;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
color: #34345c
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar_left {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
img.thumb {
|
||||||
|
max-width: 300px;
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread {
|
||||||
|
padding: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
|
margin: 2%;
|
||||||
|
background-color: #d6daf0;
|
||||||
|
min-width: 500px;
|
||||||
|
width: 75%;
|
||||||
|
border: 2px solid #B7C5D9;
|
||||||
|
border-radius: 2px 4px 4px 4px;
|
||||||
|
border-left: none;
|
||||||
|
border-top: none;
|
||||||
|
padding: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post > .header {
|
||||||
|
padding-bottom: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postbody {
|
||||||
|
font-family: serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #028241;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #480188;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cite {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.redtext {
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greentext {
|
||||||
|
color: green;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes psych {
|
||||||
|
0% {background-color: red; color: blue; }
|
||||||
|
10% {background-color: yellow; color: red; }
|
||||||
|
20% {background-color: blue; color: green; }
|
||||||
|
30% {background-color: green; color: yellow; }
|
||||||
|
40% {background-color: red; color: blue; }
|
||||||
|
50% {background-color: yellow; color: green; }
|
||||||
|
60% {background-color: blue; color: yellow; }
|
||||||
|
70% {background-color: green; color: blue; }
|
||||||
|
80% {background-color: red; color: green; }
|
||||||
|
90% {background-color: yellow; color: red; }
|
||||||
|
95% {background-color: blue; color: yellow; }
|
||||||
|
100% {background-color: green; color: white; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.psy {
|
||||||
|
animation: psych 2s linear infinite;
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
from django import template
|
||||||
|
from django.template.defaultfilters import stringfilter
|
||||||
|
|
||||||
|
from django.utils.html import conditional_escape
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
|
||||||
|
from nntpchan.frontend.models import Newsgroup, Post
|
||||||
|
|
||||||
|
import re
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
re_postcite = re.compile('>> ?([0-9a-fA-F]+)')
|
||||||
|
re_boardlink = re.compile('>>> ?([a-zA-Z0-9\.]+[a-zA-Z0-9])')
|
||||||
|
re_redtext = re.compile('== ?(.+) ?==')
|
||||||
|
re_psytext = re.compile('@@ ?(.+) ?@@')
|
||||||
|
|
||||||
|
def greentext(text, esc):
|
||||||
|
return_text = ''
|
||||||
|
f = False
|
||||||
|
for line in text.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if len(line) == 0:
|
||||||
|
continue
|
||||||
|
if line[0] == '>' and line[1] != '>':
|
||||||
|
return_text += '<span class="greentext">%s </span>' % esc ( line ) + '\n'
|
||||||
|
f = True
|
||||||
|
else:
|
||||||
|
return_text += line + '\n'
|
||||||
|
return return_text, f
|
||||||
|
|
||||||
|
def blocktext(text, esc, delim='', css='', tag='span'):
|
||||||
|
parts = text.split(delim)
|
||||||
|
f = False
|
||||||
|
if len(parts) > 1:
|
||||||
|
parts.reverse()
|
||||||
|
return_text = ''
|
||||||
|
while len(parts) > 0:
|
||||||
|
return_text += esc(parts.pop())
|
||||||
|
if len(parts) > 0:
|
||||||
|
f = True
|
||||||
|
return_text += '<{} class="{}">%s</{}>'.format(tag,css,tag) % esc(parts.pop())
|
||||||
|
return return_text, f
|
||||||
|
else:
|
||||||
|
return text, f
|
||||||
|
|
||||||
|
redtext = lambda t, e : blocktext(t, e, '==', 'redtext')
|
||||||
|
psytext = lambda t, e : blocktext(t, e, '@@', 'psy')
|
||||||
|
codeblock = lambda t, e : blocktext(t, e, '[code]', 'code', 'pre')
|
||||||
|
|
||||||
|
|
||||||
|
def postcite(text, esc):
|
||||||
|
return_text = ''
|
||||||
|
filtered = False
|
||||||
|
for line in text.split('\n'):
|
||||||
|
for word in line.split(' '):
|
||||||
|
match = re_postcite.match(word)
|
||||||
|
if match:
|
||||||
|
posthash = match.groups()[0]
|
||||||
|
posts = Post.objects.filter(posthash__startswith=posthash)
|
||||||
|
if len(posts) > 0:
|
||||||
|
filtered = True
|
||||||
|
return_text += '<a href="%s" class="postcite">>>%s</a> ' % ( posts[0].get_absolute_url(), posthash)
|
||||||
|
else:
|
||||||
|
return_text += '<span class="greentext">>>%s</span> ' % match.string
|
||||||
|
elif filtered:
|
||||||
|
return_text += word + ' '
|
||||||
|
else:
|
||||||
|
return_text += esc(word) + ' '
|
||||||
|
return_text += '\n'
|
||||||
|
return return_text, filtered
|
||||||
|
|
||||||
|
|
||||||
|
def boardlink(text, esc):
|
||||||
|
return_text = ''
|
||||||
|
filtered = False
|
||||||
|
for line in text.split('\n'):
|
||||||
|
for word in line.split(' '):
|
||||||
|
match = re_boardlink.match(word)
|
||||||
|
if match:
|
||||||
|
name = match.groups()[0]
|
||||||
|
group = Newsgroup.objects.filter(name=name)
|
||||||
|
if len(group) > 0:
|
||||||
|
filtered = True
|
||||||
|
return_text += '<a href="%s" class="boardlink">%s</a> ' % ( group[0].get_absolute_url(), esc(match.string ) )
|
||||||
|
else:
|
||||||
|
return_text += '<span class="greentext">%s</span> ' % esc (match.string)
|
||||||
|
elif filtered:
|
||||||
|
return_text += word + ' '
|
||||||
|
else:
|
||||||
|
return_text += esc(word) + ' '
|
||||||
|
return_text += '\n'
|
||||||
|
return return_text, filtered
|
||||||
|
|
||||||
|
|
||||||
|
def urlify(text, esc):
|
||||||
|
return_text = ''
|
||||||
|
filtered = False
|
||||||
|
for line in text.split('\n'):
|
||||||
|
for word in line.split(' '):
|
||||||
|
u = urlparse(word)
|
||||||
|
if u.scheme != '' and u.netloc != '':
|
||||||
|
return_text += '<a href="%s">%s</a> ' % ( u.geturl(), esc(word) )
|
||||||
|
filtered = True
|
||||||
|
else:
|
||||||
|
return_text += esc(word) + ' '
|
||||||
|
return_text += '\n'
|
||||||
|
return return_text, filtered
|
||||||
|
|
||||||
|
line_funcs = [
|
||||||
|
greentext,
|
||||||
|
redtext,
|
||||||
|
postcite,
|
||||||
|
boardlink,
|
||||||
|
urlify,
|
||||||
|
psytext,
|
||||||
|
codeblock,
|
||||||
|
]
|
||||||
|
|
||||||
|
@register.filter(needs_autoescape=True, name='memepost')
|
||||||
|
def memepost(text, autoescape=True):
|
||||||
|
if autoescape:
|
||||||
|
esc = conditional_escape
|
||||||
|
else:
|
||||||
|
esc = lambda x : x
|
||||||
|
return_text = text
|
||||||
|
|
||||||
|
def doFilter(funcs, text, filter):
|
||||||
|
"""
|
||||||
|
RECURSIVE FUNCTIONS ARE FUN :^DDDDDD
|
||||||
|
"""
|
||||||
|
if len(funcs) == 1:
|
||||||
|
t, filtered = funcs[0](text, lambda x : x)
|
||||||
|
return t
|
||||||
|
else:
|
||||||
|
t, filtered = funcs[0](text, filter)
|
||||||
|
if filtered:
|
||||||
|
return doFilter(funcs[1:], t, lambda x : x)
|
||||||
|
else:
|
||||||
|
return doFilter(funcs[1:], t, filter)
|
||||||
|
|
||||||
|
return mark_safe(doFilter(line_funcs, return_text, conditional_escape))
|
||||||
|
|
@ -4,13 +4,14 @@ from django.views import generic
|
|||||||
|
|
||||||
from .models import Post, Newsgroup
|
from .models import Post, Newsgroup
|
||||||
|
|
||||||
class BoardView(generic.ListView):
|
class BoardView(generic.View):
|
||||||
template_name = 'frontend/board.html'
|
template_name = 'frontend/board.html'
|
||||||
|
context_object_name = 'threads'
|
||||||
model = Post
|
model = Post
|
||||||
|
|
||||||
def get_queryset(self):
|
def get(self, request, name, page):
|
||||||
newsgroup = self.kwargs['name']
|
newsgroup = 'overchan.{}'.format(name)
|
||||||
page = int(self.kwargs['page'] or "0")
|
page = int(page or "0")
|
||||||
try:
|
try:
|
||||||
group = Newsgroup.objects.get(name=newsgroup)
|
group = Newsgroup.objects.get(name=newsgroup)
|
||||||
except Newsgroup.DoesNotExist:
|
except Newsgroup.DoesNotExist:
|
||||||
@ -18,12 +19,14 @@ class BoardView(generic.ListView):
|
|||||||
else:
|
else:
|
||||||
begin = page * group.posts_per_page
|
begin = page * group.posts_per_page
|
||||||
end = begin + group.posts_per_page
|
end = begin + group.posts_per_page
|
||||||
return get_object_or_404(self.model, newsgroup=group)[begin:end]
|
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})
|
||||||
|
|
||||||
|
|
||||||
class ThreadView(generic.ListView):
|
class ThreadView(generic.ListView):
|
||||||
template_name = 'frontend/thread.html'
|
template_name = 'frontend/thread.html'
|
||||||
model = Post
|
model = Post
|
||||||
|
context_object_name = 'op'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return get_object_or_404(self.model, posthash=self.kwargs['op'])
|
return get_object_or_404(self.model, posthash=self.kwargs['op'])
|
||||||
|
@ -123,4 +123,5 @@ USE_TZ = True
|
|||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
MEDIA_ROOT = '/tmp/'
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<div id="navbar">
|
<div id="navbar">
|
||||||
<span id="navbar_title">{% block navbar_title %}nntpchan{% endblock %}</span> |
|
<span id="navbar_title">{% block navbar_title %}nntpchan{% endblock %}</span> |
|
||||||
<span id="navbar_links">{% block navbar_links %}{% 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>
|
<span id="navbar_left">{% block navbar_left %}| <a href="#" onclick="nntpchan_toggle_settings()">settings</a>{% endblock %}</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -1 +1,43 @@
|
|||||||
|
|
||||||
{% extends "frontend/base.html" %}
|
{% extends "frontend/base.html" %}
|
||||||
|
{% load chanup %}
|
||||||
|
{% block title %} {{name}} page {{page}} {% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<hr />
|
||||||
|
{% for op in threads %}
|
||||||
|
<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="cite"><a href="{{op.get_absolute_url}}">>>{{op.shorthash}}</a></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="attachments">
|
||||||
|
{% for a in op.attachments.all %}
|
||||||
|
<img src="{{a.thumb}}"></img>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<pre class="postbody">{{op.message|memepost}}</pre>
|
||||||
|
</div>
|
||||||
|
{% for reply in op.get_board_replies %}
|
||||||
|
<div class="post reply">
|
||||||
|
<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="cite"><a href="{{reply.get_absolute_url}}">>>{{reply.shorthash}}</a></span>
|
||||||
|
</div>
|
||||||
|
<div class="attachments">
|
||||||
|
{% for a in reply.attachments.all %}
|
||||||
|
<img src="{{a.thumb}}"></img>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<pre class="postbody">{{reply.message|memepost}}</pre>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
{% extends "frontend/base.html" %}
|
||||||
|
{% load chanup %}
|
||||||
|
{% block title %} {{op.subject}} {% 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="cite"><a href="{{op.get_absolute_url}}">>>{{op.shorthash}}</a></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="attachments">
|
||||||
|
{% for a in op.attachments.all %}
|
||||||
|
<img class="thumb" src="{{a.thumb}}"></img>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<pre class="postbody">{{op.message|memepost}}</pre>
|
||||||
|
</div>
|
||||||
|
{% for reply in op.get_all_replies %}
|
||||||
|
<div class="post reply">
|
||||||
|
<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="cite"><a href="{{reply.get_absolute_url}}">>>{{reply.shorthash}}</a></span>
|
||||||
|
</div>
|
||||||
|
<div class="attachments">
|
||||||
|
{% for a in reply.attachments.all %}
|
||||||
|
<img class="thumb" src="{{a.thumb}}"></img>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% autoescape off %}
|
||||||
|
<pre class="postbody">{{reply.message|memepost}}</pre>
|
||||||
|
{% endautoescape %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
{% endblock %}
|
22
contrib/frontends/django/nntpchan/nntpchan/thumbnail.py
Normal file
22
contrib/frontends/django/nntpchan/nntpchan/thumbnail.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
img_ext = []
|
||||||
|
vid_ext = []
|
||||||
|
|
||||||
|
def generate(fname, tname, placeholder):
|
||||||
|
"""
|
||||||
|
generate thumbnail
|
||||||
|
"""
|
||||||
|
ext = fname.split('.')[-1]
|
||||||
|
cmd = None
|
||||||
|
if ext in img_ext:
|
||||||
|
cmd = ['convert', '-thumbnail', '200', fname, tname]
|
||||||
|
elif ext in vid_ext:
|
||||||
|
cmd = ['ffmpeg', '-i', fname, '-vf', 'scale=300:200', '-vframes', '1', tname]
|
||||||
|
|
||||||
|
if cmd is None:
|
||||||
|
os.link(placeholder, tname)
|
||||||
|
else:
|
||||||
|
subprocess.call(cmd)
|
||||||
|
|
||||||
|
|
@ -14,10 +14,12 @@ Including another URLconf
|
|||||||
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^webhook$', views.webhook),
|
url(r'^webhook$', views.webhook),
|
||||||
url(r'', include('nntpchan.frontend.urls'))
|
url(r'', include('nntpchan.frontend.urls'))
|
||||||
]
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
@ -5,6 +5,8 @@ from django.views.decorators.csrf import csrf_exempt
|
|||||||
from .frontend.models import Post, Attachment, Newsgroup
|
from .frontend.models import Post, Attachment, Newsgroup
|
||||||
from .frontend import util
|
from .frontend import util
|
||||||
|
|
||||||
|
from . import thumbnail
|
||||||
|
|
||||||
import email
|
import email
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -74,10 +76,15 @@ def webhook(request):
|
|||||||
mtype = part.get_content_type()
|
mtype = part.get_content_type()
|
||||||
ext = mimetypes.guess_extension(mtype) or ''
|
ext = mimetypes.guess_extension(mtype) or ''
|
||||||
fh = util.hashfile(bytes(payload))
|
fh = util.hashfile(bytes(payload))
|
||||||
fname = os.path.join(settings.MEDIA_ROOT, fh+ext)
|
fn = fh + ext
|
||||||
|
fname = os.path.join(settings.MEDIA_ROOT, fn)
|
||||||
if not os.path.exists(fname):
|
if not os.path.exists(fname):
|
||||||
with open(fname, 'wb') as f:
|
with open(fname, 'wb') as f:
|
||||||
f.write(payload)
|
f.write(payload)
|
||||||
|
tname = os.path.join(settings.MEDIA_ROOT, 'thumb-{}.jpg'.format(fn))
|
||||||
|
placeholder = os.path.join(settings.MEDIA_ROOT, 'placeholder.jpg')
|
||||||
|
if not os.path.exists(tname):
|
||||||
|
thumbnail.generate(fname, tname, placeholder)
|
||||||
|
|
||||||
att = Attachment(filehash=fh)
|
att = Attachment(filehash=fh)
|
||||||
att.mimetype = mtype
|
att.mimetype = mtype
|
||||||
|
Reference in New Issue
Block a user