# Path: gallery/imgutil.py
# def make_thumbnail(image_name, thumb_name, preset,
#                    image_storage, thumb_storage):
# 
#     options = getattr(settings, 'GALLERY_RESIZE_OPTIONS', {})
#     presets = getattr(settings, 'GALLERY_RESIZE_PRESETS', {})
# 
#     # Load the image
#     image = Image.open(image_storage.open(image_name))
#     format = image.format
# 
#     if format == 'JPEG':
#         # Auto-rotate JPEG files based on EXIF information
#         try:                                                # pragma: no cover
#             # Use of an undocumented API — let's catch exceptions liberally
#             orientation = image._getexif()[274]
#             image = exif_rotations[orientation](image)
#         except Exception:
#             pass
# 
#         # Increase Pillow's buffer from 64k to 4MB to avoid JPEG save errors
#         ImageFile.MAXBLOCK = 4194304
# 
#     # Pre-crop if requested and the aspect ratios don't match exactly
#     image_width, image_height = image.size
#     thumb_width, thumb_height, crop = presets[preset]
#     if crop:
#         if thumb_width * image_height > image_width * thumb_height:
#             target_height = image_width * thumb_height // thumb_width
#             top = (image_height - target_height) // 2
#             image = image.crop((0, top, image_width, top + target_height))
#         elif thumb_width * image_height < image_width * thumb_height:
#             target_width = image_height * thumb_width // thumb_height
#             left = (image_width - target_width) // 2
#             image = image.crop((left, 0, left + target_width, image_height))
# 
#     # Resize
#     image.thumbnail((thumb_width, thumb_height), Image.ANTIALIAS)
# 
#     # Save the thumbnail
#     thumb_bytes_io = io.BytesIO()
#     image.save(thumb_bytes_io, format, **options.get(image.format, {}))
#     thumb_bytes_io.seek(0)
#     thumb_storage.save(thumb_name, thumb_bytes_io)
# 
# Path: gallery/storages.py
# @functools.lru_cache()
# def get_storage(name):
#     name = name.upper()
#     storage_setting = f'GALLERY_{name}_STORAGE'
#     dir_setting = f'GALLERY_{name}_DIR'
#     try:
#         storage_class = getattr(settings, storage_setting)
#     except AttributeError:
#         # There's a good chance that this fallback will survive for a long
#         # time because deprecating it would require updating all the tests.
#         try:
#             storage_dir = getattr(settings, dir_setting)
#         except AttributeError:
#             raise ImproperlyConfigured(
#                 f"Please define {storage_setting} or {dir_setting}")
#         else:
#             return FileSystemStorage(location=storage_dir)
#     else:
#         return import_string(storage_class)()


import hashlib
import os
from django.conf import settings
from django.contrib.auth.models import Group, User
from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from .imgutil import make_thumbnail
from .storages import get_storage


class AccessPolicy(models.Model):
    public = models.BooleanField(verbose_name="is public", default=False)
    groups = models.ManyToManyField(Group, blank=True, verbose_name="authorized groups")
    users = models.ManyToManyField(User, blank=True, verbose_name="authorized users")

    class Meta:
        abstract = True

    def allows(self, user):
        if self.public:
            return True
        if user.is_authenticated:
            if set(self.groups.all()) & set(user.groups.all()):
                return True
            if user in self.users.all():
                return True
        return False


class AlbumManager(models.Manager):

    def allowed_for_user(self, user, include_public=True):
        album_cond = Q()
        if include_public:
            album_cond |= Q(access_policy__public=True)
        if user.is_authenticated:
            album_cond |= Q(access_policy__users=user)
            album_cond |= Q(access_policy__groups__user=user)

# Path: gallery/imgutil.py
# def make_thumbnail(image_name, thumb_name, preset,
#                    image_storage, thumb_storage):
# 
#     options = getattr(settings, 'GALLERY_RESIZE_OPTIONS', {})
#     presets = getattr(settings, 'GALLERY_RESIZE_PRESETS', {})
# 
#     # Load the image
#     image = Image.open(image_storage.open(image_name))
#     format = image.format
# 
#     if format == 'JPEG':
#         # Auto-rotate JPEG files based on EXIF information
#         try:                                                # pragma: no cover
#             # Use of an undocumented API — let's catch exceptions liberally
#             orientation = image._getexif()[274]
#             image = exif_rotations[orientation](image)
#         except Exception:
#             pass
# 
#         # Increase Pillow's buffer from 64k to 4MB to avoid JPEG save errors
#         ImageFile.MAXBLOCK = 4194304
# 
#     # Pre-crop if requested and the aspect ratios don't match exactly
#     image_width, image_height = image.size
#     thumb_width, thumb_height, crop = presets[preset]
#     if crop:
#         if thumb_width * image_height > image_width * thumb_height:
#             target_height = image_width * thumb_height // thumb_width
#             top = (image_height - target_height) // 2
#             image = image.crop((0, top, image_width, top + target_height))
#         elif thumb_width * image_height < image_width * thumb_height:
#             target_width = image_height * thumb_width // thumb_height
#             left = (image_width - target_width) // 2
#             image = image.crop((left, 0, left + target_width, image_height))
# 
#     # Resize
#     image.thumbnail((thumb_width, thumb_height), Image.ANTIALIAS)
# 
#     # Save the thumbnail
#     thumb_bytes_io = io.BytesIO()
#     image.save(thumb_bytes_io, format, **options.get(image.format, {}))
#     thumb_bytes_io.seek(0)
#     thumb_storage.save(thumb_name, thumb_bytes_io)
# 
# Path: gallery/storages.py
# @functools.lru_cache()
# def get_storage(name):
#     name = name.upper()
#     storage_setting = f'GALLERY_{name}_STORAGE'
#     dir_setting = f'GALLERY_{name}_DIR'
#     try:
#         storage_class = getattr(settings, storage_setting)
#     except AttributeError:
#         # There's a good chance that this fallback will survive for a long
#         # time because deprecating it would require updating all the tests.
#         try:
#             storage_dir = getattr(settings, dir_setting)
#         except AttributeError:
#             raise ImproperlyConfigured(
#                 f"Please define {storage_setting} or {dir_setting}")
#         else:
#             return FileSystemStorage(location=storage_dir)
#     else:
#         return import_string(storage_class)()


# Path: gallery/models.py
import hashlib
import os
from django.conf import settings
from django.contrib.auth.models import Group, User
from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from .imgutil import make_thumbnail
from .storages import get_storage



class AccessPolicy(models.Model):
    public = models.BooleanField(verbose_name="is public", default=False)
    groups = models.ManyToManyField(Group, blank=True, verbose_name="authorized groups")
    users = models.ManyToManyField(User, blank=True, verbose_name="authorized users")

    class Meta:
        abstract = True

    def allows(self, user):
        if self.public:
            return True
        if user.is_authenticated:
            if set(self.groups.all()) & set(user.groups.all()):
                return True
            if user in self.users.all():
                return True
        return False


class AlbumManager(models.Manager):

    def allowed_for_user(self, user, include_public=True):
        album_cond = Q()
        if include_public:
            album_cond |= Q(access_policy__public=True)
        if user.is_authenticated:
            album_cond |= Q(access_policy__users=user)
            album_cond |= Q(access_policy__groups__user=user)

        return self.filter(album_cond).distinct()