import os
import shutil
import subprocess
from itertools import zip_longest
from PIL import Image
from django.conf import settings
from django.core.validators import MinValueValidator, FileExtensionValidator
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from utils.threading import PopenAndCall
[docs]def thabloid_filename(instance, filename):
"""Return path of thabloid."""
ext = os.path.splitext(filename)[1]
return os.path.join("private/thabloids/", slugify(instance) + ext)
[docs]def pagesets(count):
if count < 1:
return []
pageiter = iter(range(2, count))
return [(1, None)] + list(zip_longest(pageiter, pageiter))
[docs]class Thabloid(models.Model):
"""Model representing a Thabloid."""
year = models.IntegerField(
verbose_name="academic year", validators=[MinValueValidator(1990)]
)
issue = models.IntegerField()
file = models.FileField(
upload_to=thabloid_filename,
validators=[FileExtensionValidator(["txt", "pdf", "jpg", "jpeg", "png"])],
)
class Meta:
"""Meta class for Thabloid model."""
unique_together = (
"year",
"issue",
)
ordering = ("-year", "-issue")
def __str__(self):
"""Return string representation of a Thabloid object."""
return "Thabloid {}-{}, #{}".format(self.year, self.year + 1, self.issue)
[docs] def page_url(self, page=None, second_page=None):
"""Return path of Thabloid pages image."""
if page is None:
page = "%03d.png"
elif second_page is None:
page = "{:03}.png".format(page)
else:
page = "{:03}-{:03}.png".format(page, second_page)
dst, _ = os.path.splitext(self.file.name)
return os.path.join(os.path.dirname(dst), "pages", os.path.basename(dst), page)
@property
def cover(self):
"""Return first page as cover."""
return self.page_url(1)
[docs] def pagesets(self, count):
"""Return list of pages to should be shown together."""
if count < 1:
return []
pageiter = iter(range(2, count))
return [(1, None)] + list(zip_longest(pageiter, pageiter))
@property
def pages(self):
"""Return urls of pages that should be shown together."""
pages = os.listdir(
os.path.join(settings.MEDIA_ROOT, os.path.dirname(self.page_url()))
)
count = len(pages) * 2 - 1
return map(lambda p: self.page_url(p[0], p[1]), pagesets(count))
[docs] def get_absolute_url(self):
"""Get url of Thabloid."""
return reverse(
"thabloid:pages", kwargs={"year": self.year, "issue": self.issue}
)
[docs] def save(self, *args, wait=False, **kwargs):
"""Save Thabloid to disk."""
new_file = False
if self.pk is None:
new_file = True
else:
old = Thabloid.objects.get(pk=self.pk)
old_dir = os.path.join(settings.MEDIA_ROOT, old.page_url())
old_dir = os.path.dirname(old_dir)
if self.file != old.file:
new_file = True
elif self.year != old.year or self.issue != old.issue:
self.file.name = thabloid_filename(self, self.file.name)
new_dir = os.path.join(settings.MEDIA_ROOT, self.page_url())
new_dir = os.path.dirname(new_dir)
try:
shutil.rmtree(new_dir)
except FileNotFoundError:
pass
os.rename(old_dir, new_dir)
os.rename(
os.path.join(settings.MEDIA_ROOT, old.file.name),
os.path.join(settings.MEDIA_ROOT, self.file.name),
)
if new_file:
filename = thabloid_filename(self, self.file.name)
src = os.path.join(settings.MEDIA_ROOT, filename)
# Removes the .pdf file if it already exists
try:
os.remove(src)
except FileNotFoundError:
pass
super().save(*args, **kwargs)
if new_file:
self.extract_thabloid_pages(wait)