Add image upload support

Images can be uploaded, thumbnails are created, they're displayed within
the threads themselves. Just like four chans!

There is not an upload size limit set yet. Gotta get on that next.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2022-05-04 19:45:36 -07:00
parent 7b99830e65
commit e6c60ff93c
11 changed files with 201 additions and 61 deletions

View File

@@ -1,8 +1,42 @@
import os
from pathlib import Path
from django.db import models
from django.db.models.signals import post_save
from django.db.models import signals
from django.conf import settings
from django.core.files.base import ContentFile
from django.dispatch import receiver
from django.urls import reverse
from django.utils import timezone
from PIL import Image
from io import BytesIO
def image_upload(instance, filename):
op_id = instance.op.id if instance.op else instance.id
now = timezone.now()
now_sec = now.strftime("%s.%f")
ext = Path(filename).suffix.lower()
if ext in (".jpeg", ".jpg"):
ext = ".jpg"
if ext not in (".jpg", ".png", ".gif"):
raise Exception("File type invalid")
if instance.op:
return f"{instance.board.url}/{instance.op.id}/{now_sec}{ext}"
else:
return f"{instance.board.url}/{now_sec}{ext}"
def thumbs_upload(instance, filename):
op_id = instance.op.id if instance.op else instance.id
now = timezone.now()
now_sec = now.strftime("%s.%f")
ext = Path(filename).suffix.lower()
if instance.op:
return f"{instance.board.url}/{instance.op.id}/{now_sec}{ext}"
else:
return f"{instance.board.url}/{now_sec}t{ext}"
class Board(models.Model):
@@ -39,8 +73,52 @@ class Post(models.Model):
created = models.DateTimeField(auto_now_add=True)
# Last bump time
last_bump = models.DateTimeField(auto_now_add=True)
# Image
image = models.ImageField(
upload_to=image_upload,
null=True,
blank=True,
width_field="image_width",
height_field="image_height",
)
# Thumbnail
thumbnail = models.ImageField(upload_to=thumbs_upload, editable=False, null=True)
# Original image name
original_image_name = models.CharField(max_length=255, null=True)
# Image width and height
image_width = models.IntegerField(null=True)
image_height = models.IntegerField(null=True)
# TODO : images
def save(self, *args, **kwargs):
if self.image:
self.original_image_name = self.image.name
self.__make_thumbnail()
super(Post, self).save(*args, **kwargs)
def __make_thumbnail(self):
image = Image.open(self.image)
image.thumbnail(settings.THUMB_SIZE, Image.ANTIALIAS)
image_path = Path(self.image.name)
thumb_path = Path(image_path.stem + "t" + image_path.suffix)
ext = thumb_path.suffix.lower()
if ext in (".jpg", ".jpeg"):
FTYPE = "JPEG"
elif ext == ".gif":
FTYPE = "GIF"
elif ext == ".png":
FTYPE = "PNG"
else:
raise Exception("File type invalid")
thumb_temp = BytesIO()
image.save(thumb_temp, FTYPE)
thumb_temp.seek(0)
# save=False stops recursion
self.thumbnail.save(thumb_path, ContentFile(thumb_temp.read()), save=False)
thumb_temp.close()
def get_absolute_url(self):
if self.op is None:
@@ -57,8 +135,16 @@ class Post(models.Model):
)
@receiver(post_save, sender=Post)
@receiver(signals.post_save, sender=Post)
def post_created(sender, instance, created, **kwargs):
if created and instance.op:
instance.op.last_bump = timezone.now()
instance.op.save()
@receiver(signals.post_delete, sender=Post)
def post_deleted(sender, instance, **kwargs):
if instance.image and Path(instance.image.path).is_file():
os.remove(instance.image.path)
if instance.thumbnail and Path(instance.thumbnail.path).is_file():
os.remove(instance.thumbnail.path)