You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

123 lines
3.6 KiB

  1. import PIL.Image
  2. import requests
  3. from io import BytesIO
  4. from django.conf import settings
  5. from django.core.files.uploadedfile import InMemoryUploadedFile
  6. from django.db import models
  7. from django.dispatch import receiver
  8. from django_images.models import Image as BaseImage, Thumbnail
  9. from taggit.managers import TaggableManager
  10. from users.models import User
  11. class ImageManager(models.Manager):
  12. _default_ua = {
  13. 'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) '
  14. 'AppleWebKit/537.36 (KHTML, like Gecko) '
  15. 'Chrome/48.0.2564.82 Safari/537.36',
  16. }
  17. @staticmethod
  18. def _is_valid_image(fp):
  19. fp.seek(0)
  20. try:
  21. PIL.Image.open(fp)
  22. except PIL.UnidentifiedImageError:
  23. fp.seek(0)
  24. return False
  25. else:
  26. fp.seek(0)
  27. return True
  28. # FIXME: Move this into an asynchronous task
  29. def create_for_url(self, url, referer=None):
  30. file_name = url.split("/")[-1].split('#')[0].split('?')[0]
  31. buf = BytesIO()
  32. headers = dict(self._default_ua)
  33. if referer is not None:
  34. headers["Referer"] = referer
  35. response = requests.get(url, headers=headers)
  36. buf.write(response.content)
  37. if not self._is_valid_image(buf):
  38. return None
  39. obj = InMemoryUploadedFile(buf, 'image', file_name,
  40. None, buf.tell(), None)
  41. # create the image and its thumbnails in one transaction, removing
  42. # a chance of getting Database into a inconsistent state when we
  43. # try to create thumbnails one by one later
  44. image = self.create(image=obj)
  45. Thumbnail.objects.get_or_create_at_sizes(image, settings.IMAGE_SIZES.keys())
  46. return image
  47. class Image(BaseImage):
  48. objects = ImageManager()
  49. class Sizes:
  50. standard = "standard"
  51. thumbnail = "thumbnail"
  52. square = "square"
  53. class Meta:
  54. proxy = True
  55. @property
  56. def standard(self):
  57. return Thumbnail.objects.get(
  58. original=self, size=self.Sizes.standard
  59. )
  60. @property
  61. def thumbnail(self):
  62. return Thumbnail.objects.get(
  63. original=self, size=self.Sizes.thumbnail
  64. )
  65. @property
  66. def square(self):
  67. return Thumbnail.objects.get(
  68. original=self, size=self.Sizes.square
  69. )
  70. class Board(models.Model):
  71. class Meta:
  72. unique_together = ("submitter", "name")
  73. index_together = ("submitter", "name")
  74. submitter = models.ForeignKey(User, on_delete=models.CASCADE)
  75. name = models.CharField(max_length=128, blank=False, null=False)
  76. private = models.BooleanField(default=False, blank=False)
  77. pins = models.ManyToManyField("Pin", related_name="pins", blank=True)
  78. published = models.DateTimeField(auto_now_add=True)
  79. class Pin(models.Model):
  80. submitter = models.ForeignKey(User, on_delete=models.CASCADE)
  81. private = models.BooleanField(default=False, blank=False)
  82. url = models.CharField(null=True, blank=True, max_length=2048)
  83. referer = models.CharField(null=True, blank=True, max_length=2048)
  84. description = models.TextField(blank=True, null=True)
  85. image = models.ForeignKey(Image, related_name='pin', on_delete=models.CASCADE)
  86. published = models.DateTimeField(auto_now_add=True)
  87. tags = TaggableManager()
  88. def tag_list(self):
  89. return self.tags.all()
  90. def __unicode__(self):
  91. return '%s - %s' % (self.submitter, self.published)
  92. @receiver(models.signals.post_delete, sender=Pin)
  93. def delete_pin_images(sender, instance, **kwargs):
  94. try:
  95. instance.image.delete()
  96. except Image.DoesNotExist:
  97. pass