|
|
from itertools import zip_longest
|
|
|
|
|
|
import boards
|
|
|
from boards.models import STATUS_ARCHIVE
|
|
|
from django.core.files.images import get_image_dimensions
|
|
|
from django.db import models
|
|
|
|
|
|
from boards import utils
|
|
|
from boards.models.attachment.viewers import get_viewers, AbstractViewer, \
|
|
|
FILE_TYPES_IMAGE
|
|
|
from boards.utils import get_upload_filename, get_extension, cached_result
|
|
|
|
|
|
|
|
|
class AttachmentManager(models.Manager):
|
|
|
def create_with_hash(self, file):
|
|
|
file_hash = utils.get_file_hash(file)
|
|
|
attachment = self._get_existing(file_hash, file)
|
|
|
if not attachment:
|
|
|
# FIXME Use full mimetype here, need to modify viewers too
|
|
|
file_type = get_extension(file.name)
|
|
|
attachment = self.create(file=file, mimetype=file_type,
|
|
|
hash=file_hash)
|
|
|
|
|
|
return attachment
|
|
|
|
|
|
def create_from_url(self, url):
|
|
|
existing = self.filter(url=url)
|
|
|
if len(existing) > 0:
|
|
|
attachment = existing[0]
|
|
|
else:
|
|
|
attachment = self.create(url=url)
|
|
|
return attachment
|
|
|
|
|
|
def get_random_images(self, count, tags=None):
|
|
|
images = self.filter(mimetype__in=FILE_TYPES_IMAGE).exclude(
|
|
|
attachment_posts__thread__status=STATUS_ARCHIVE)
|
|
|
if tags is not None:
|
|
|
images = images.filter(attachment_posts__threads__tags__in=tags)
|
|
|
return images.order_by('?')[:count]
|
|
|
|
|
|
def _get_existing(self, file_hash, file):
|
|
|
"""
|
|
|
Gets an attachment with the same file if one exists.
|
|
|
"""
|
|
|
existing = self.filter(hash=file_hash)
|
|
|
attachment = None
|
|
|
for existing_attachment in existing:
|
|
|
equal = True
|
|
|
existing_file = existing_attachment.file
|
|
|
for chunk, existing_chunk in zip_longest(file.chunks(), existing_file.chunks()):
|
|
|
if chunk != existing_chunk:
|
|
|
equal = False
|
|
|
break
|
|
|
if equal:
|
|
|
attachment = existing[0]
|
|
|
return attachment
|
|
|
|
|
|
|
|
|
class Attachment(models.Model):
|
|
|
objects = AttachmentManager()
|
|
|
|
|
|
class Meta:
|
|
|
app_label = 'boards'
|
|
|
ordering = ('id',)
|
|
|
|
|
|
file = models.FileField(upload_to=get_upload_filename, null=True)
|
|
|
mimetype = models.CharField(max_length=50, null=True)
|
|
|
hash = models.CharField(max_length=36, null=True)
|
|
|
alias = models.TextField(unique=True, null=True)
|
|
|
url = models.TextField(blank=True, default='')
|
|
|
|
|
|
def get_view(self):
|
|
|
file_viewer = None
|
|
|
for viewer in get_viewers():
|
|
|
if viewer.supports(self.mimetype):
|
|
|
file_viewer = viewer
|
|
|
break
|
|
|
if file_viewer is None:
|
|
|
file_viewer = AbstractViewer
|
|
|
|
|
|
return file_viewer(self.file, self.mimetype, self.hash, self.url).get_view()
|
|
|
|
|
|
def __str__(self):
|
|
|
return self.url or self.file.url
|
|
|
|
|
|
def get_random_associated_post(self):
|
|
|
posts = boards.models.Post.objects.filter(attachments__in=[self])
|
|
|
return posts.order_by('?').first()
|
|
|
|
|
|
@cached_result()
|
|
|
def get_size(self):
|
|
|
if self.file:
|
|
|
if self.mimetype in FILE_TYPES_IMAGE:
|
|
|
return get_image_dimensions(self.file)
|
|
|
else:
|
|
|
return 200, 150
|
|
|
|
|
|
def get_thumb_url(self):
|
|
|
split = self.file.url.rsplit('.', 1)
|
|
|
w, h = 200, 150
|
|
|
return '%s.%sx%s.%s' % (split[0], w, h, split[1])
|
|
|
|
|
|
@cached_result()
|
|
|
def get_preview_size(self):
|
|
|
if self.mimetype in FILE_TYPES_IMAGE:
|
|
|
preview_path = self.file.path.replace('.', '.200x150.')
|
|
|
return get_image_dimensions(preview_path)
|
|
|
else:
|
|
|
return 200, 150
|
|
|
|
|
|
def is_internal(self):
|
|
|
return self.url is None or len(self.url) == 0
|
|
|
|