Source code for photos.models

import hashlib
import logging
import os
import random

from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _

from members.models import Member
from pushnotifications.models import ScheduledMessage, Category
from utils.translation import ModelTranslateMeta, MultilingualField

COVER_FILENAME = "cover.jpg"


logger = logging.getLogger(__name__)


[docs]def photo_uploadto(instance, filename): """Get path of file to upload to.""" num = instance.album.photo_set.count() extension = os.path.splitext(filename)[1] new_filename = str(num).zfill(4) + extension return os.path.join(Album.photosdir, instance.album.dirname, new_filename)
[docs]class Photo(models.Model): """Model for a Photo object.""" album = models.ForeignKey( "Album", on_delete=models.CASCADE, verbose_name=_("album") ) file = models.ImageField(_("file"), upload_to=photo_uploadto) rotation = models.IntegerField( verbose_name=_("rotation"), default=0, choices=((x, x) for x in (0, 90, 180, 270)), help_text=_("This does not modify the original image file."), ) hidden = models.BooleanField(_("hidden"), default=False) _digest = models.CharField("digest", max_length=40,) def __init__(self, *args, **kwargs): """Initialize Photo object and set the file if it exists.""" super().__init__(*args, **kwargs) if self.file: self.original_file = self.file.path else: self.original_file = "" def __str__(self): """Return the filename of a Photo object.""" return os.path.basename(self.file.name) class Meta: """Meta class for Photo.""" ordering = ("file",)
[docs]class Album(models.Model, metaclass=ModelTranslateMeta): """Model for Album objects.""" title = MultilingualField(models.CharField, _("title"), max_length=200,) dirname = models.CharField(verbose_name=_("directory name"), max_length=200,) date = models.DateField(verbose_name=_("date"),) slug = models.SlugField(verbose_name=_("slug"), unique=True,) hidden = models.BooleanField(verbose_name=_("hidden"), default=False) new_album_notification = models.ForeignKey( ScheduledMessage, on_delete=models.deletion.SET_NULL, blank=True, null=True ) _cover = models.OneToOneField( Photo, on_delete=models.SET_NULL, blank=True, null=True, related_name="covered_album", verbose_name=_("cover image"), ) shareable = models.BooleanField(verbose_name=_("shareable"), default=False) photosdir = "photos" photospath = os.path.join(settings.MEDIA_ROOT, photosdir) @cached_property def cover(self): """Return cover of Album. If a cover is not set, return a random photo or None if there are no photos. """ cover = None if self._cover is not None: return self._cover if self.photo_set.exists(): random.seed(self.dirname) cover = random.choice(self.photo_set.all()) return cover def __str__(self): """Get string representation of Album.""" return "{} {}".format(self.date.strftime("%Y-%m-%d"), self.title)
[docs] def get_absolute_url(self): """Get url of Album.""" return reverse("photos:album", args=[str(self.slug)])
[docs] def save(self, **kwargs): """Save album and send appropriate notifications.""" # dirname is only set for new objects, to avoid ever changing it if self.pk is None: self.dirname = self.slug if not self.hidden and ( self.new_album_notification is None or not self.new_album_notification.sent ): new_album_notification_time = timezone.now() + timezone.timedelta(hours=1) new_album_notification = ScheduledMessage() if ( self.new_album_notification is not None and not self.new_album_notification.sent ): new_album_notification = self.new_album_notification new_album_notification.title_en = "New album uploaded" new_album_notification.body_en = ( f"A new photo album '{self.title_en}' has just been uploaded" ) new_album_notification.category = Category.objects.get(key=Category.PHOTO) new_album_notification.url = f"{settings.BASE_URL}{self.get_absolute_url()}" new_album_notification.time = new_album_notification_time new_album_notification.save() self.new_album_notification = new_album_notification self.new_album_notification.users.set(Member.current_members.all()) elif ( self.hidden and self.new_album_notification is not None and not self.new_album_notification.sent ): existing_notification = self.new_album_notification self.new_album_notification = None existing_notification.delete() super().save(**kwargs)
@property def access_token(self): """Return access token for album.""" return hashlib.sha256( "{}album{}".format(settings.SECRET_KEY, self.pk).encode("utf-8") ).hexdigest() class Meta: """Meta class for Album.""" ordering = ("-date", "title_en")