gremmie@1: """
gremmie@1: Models for the Photo Of The Day (POTD) application.
bgneal@515: 
gremmie@1: """
bgneal@535: import datetime
gremmie@1: import os
gremmie@1: from PIL import ImageFile
gremmie@1: from PIL import Image
gremmie@1: try:
gremmie@1:    from cStringIO import StringIO
gremmie@1: except:
gremmie@1:    from StringIO import StringIO
gremmie@1: 
gremmie@1: from django.db import models
gremmie@1: from django.contrib.auth.models import User
gremmie@1: from django.core.files.base import ContentFile
gremmie@1: 
gremmie@1: POTD_THUMB_WIDTH = 120
gremmie@1: 
gremmie@1: def scale_image(image):
gremmie@1:     (w, h) = image.size
gremmie@1:     if w <= POTD_THUMB_WIDTH:
gremmie@1:         return image
gremmie@1:     scale_factor = float(POTD_THUMB_WIDTH) / w
gremmie@1:     new_height = int(scale_factor * h)
gremmie@1:     return image.resize((POTD_THUMB_WIDTH, new_height), Image.ANTIALIAS)
gremmie@1: 
gremmie@1: 
gremmie@1: class Photo(models.Model):
gremmie@1:     """Model to represent a POTD"""
gremmie@1:     photo = models.ImageField(upload_to='potd/%Y/%m/%d')
gremmie@1:     thumb = models.ImageField(upload_to='potd/%Y/%m/%d/thumbs', blank=True, null=True)
gremmie@1:     caption = models.CharField(max_length=128)
gremmie@1:     description = models.TextField()
gremmie@1:     user = models.ForeignKey(User)
bgneal@535:     date_added = models.DateField()
gremmie@1:     potd_count = models.IntegerField(default=0)
gremmie@1: 
bgneal@14:     class Meta:
bgneal@14:         ordering = ('-date_added', '-caption')
bgneal@14: 
gremmie@1:     def __unicode__(self):
gremmie@1:         return u'%s (%s)' % (self.caption, self.pk)
gremmie@1: 
bgneal@14:     @models.permalink
bgneal@14:     def get_absolute_url(self):
bgneal@14:         return ('potd-archive', [str(self.id)])
gremmie@1: 
bgneal@182:     def save(self, *args, **kwargs):
bgneal@330:         if not self.pk:
bgneal@330:             self.generate_thumb()
bgneal@535:             self.date_added = datetime.datetime.now()
gremmie@1: 
bgneal@330:         super(Photo, self).save(*args, **kwargs)
bgneal@330: 
bgneal@330:     def can_comment_on(self):
bgneal@330:         return Current.objects.get_current_id() == self.id
bgneal@330: 
bgneal@330:     def generate_thumb(self):
gremmie@1:         if self.thumb:
gremmie@1:             self.thumb.delete(save=False)
gremmie@1: 
gremmie@1:         parser = ImageFile.Parser()
gremmie@1:         for chunk in self.photo.chunks():
gremmie@1:             parser.feed(chunk)
gremmie@1:         image = parser.close()
gremmie@1:         format = image.format
gremmie@1:         image = scale_image(image)
gremmie@1:         s = StringIO()
gremmie@1:         image.save(s, format)
gremmie@1:         thumb_name = os.path.basename(self.photo.path)
gremmie@1:         self.thumb.save(thumb_name, ContentFile(s.getvalue()), save=False)
gremmie@1: 
bgneal@491:     def ogp_tags(self):
bgneal@491:         """
bgneal@491:         Returns a dict of Open Graph Protocol meta tags.
bgneal@491: 
bgneal@491:         """
bgneal@491:         desc = "Photo of the day: %s." % self.caption
bgneal@491:         return {
bgneal@491:             'og:title': self.caption,
bgneal@491:             'og:type': 'article',
bgneal@491:             'og:url': self.get_absolute_url(),
bgneal@491:             'og:image': self.photo.url,
bgneal@491:             'og:description': desc,
bgneal@491:         }
bgneal@491: 
gremmie@1: 
gremmie@1: class CurrentManager(models.Manager):
bgneal@515:     """
bgneal@515:     Manager for the Current model.
bgneal@515: 
bgneal@515:     """
gremmie@1:     def get_current_photo(self):
bgneal@515:         """
bgneal@515:         Retrieves the current photo object from the current record.
bgneal@515: 
bgneal@515:         """
gremmie@1:         try:
gremmie@1:             c = self.get(pk=1)
gremmie@1:             return c.potd
gremmie@1:         except Current.DoesNotExist:
gremmie@1:             return None
gremmie@1: 
gremmie@1:     def get_current_id(self):
bgneal@515:         """
bgneal@515:         Returns the ID of the current POTD from the current record.
bgneal@515: 
bgneal@515:         """
gremmie@1:         potd = self.get_current_photo()
gremmie@1:         if potd is not None:
gremmie@1:             return potd.pk
gremmie@1:         return None
gremmie@1: 
gremmie@1: 
gremmie@1: class Current(models.Model):
gremmie@1:     """This model simply stores the current POTD."""
gremmie@1:     potd = models.ForeignKey(Photo)
gremmie@1: 
gremmie@1:     objects = CurrentManager()
gremmie@1: 
gremmie@1:     def __unicode__(self):
gremmie@1:         return self.potd.__unicode__()
gremmie@1: 
gremmie@1:     class Meta:
gremmie@1:         verbose_name_plural = 'Current'
gremmie@1: 
gremmie@1: 
gremmie@1: class SequenceManager(models.Manager):
bgneal@515:     """
bgneal@515:     Manager for the Sequence model.
bgneal@515: 
bgneal@515:     """
gremmie@1:     def insert_photo(self, photo_id):
bgneal@515:         """
bgneal@515:         Inserts the given photo_id just after the current photo so it
bgneal@515:         will appear as tomorrow's POTD.
bgneal@515: 
bgneal@515:         """
gremmie@1:         current = Current.objects.get_current_id()
gremmie@1:         if current is not None:
bgneal@330:             s = self.get(pk=1)
bgneal@330:             seq = [int(x) for x in s.seq.split(',')]
bgneal@330:             if photo_id not in seq:
bgneal@330:                 i = seq.index(current)
bgneal@330:                 seq.insert(i + 1, photo_id)
bgneal@330:                 s.seq = ','.join([str(x) for x in seq])
bgneal@330:                 s.save()
gremmie@1: 
gremmie@1:     def remove_photo(self, photo_id):
bgneal@515:         """
bgneal@515:         Removes a given photo id from the sequence of photos.
bgneal@515: 
bgneal@515:         """
gremmie@1:         try:
gremmie@1:             s = self.get(pk=1)
bgneal@330:         except Sequence.DoesNotExist:
bgneal@330:             pass
bgneal@330:         else:
gremmie@1:             seq = [int(x) for x in s.seq.split(',')]
gremmie@1:             if photo_id in seq:
gremmie@1:                 seq.remove(photo_id)
gremmie@1:                 s.seq = ','.join([str(x) for x in seq])
gremmie@1:                 s.save()
gremmie@1: 
gremmie@1: 
gremmie@1: class Sequence(models.Model):
gremmie@1:     """This model stores the sequence of photos for the POTD."""
gremmie@1:     seq = models.CommaSeparatedIntegerField(max_length=4096)
gremmie@1: 
gremmie@1:     objects = SequenceManager()
gremmie@1: 
gremmie@1:     def __unicode__(self):
bgneal@535:         return u'POTD Sequence %d' % self.id
gremmie@1: 
gremmie@1:     class Meta:
gremmie@1:         verbose_name_plural = 'Sequence'