Add photos API

parent 5e7f90cf
......@@ -33,6 +33,14 @@ photos\.models module
:undoc-members:
:show-inheritance:
photos\.services module
-----------------------
.. automodule:: photos.services
:members:
:undoc-members:
:show-inheritance:
photos\.urls module
-------------------
......
thaliawebsite\.api package
==========================
.. automodule:: thaliawebsite.api
:members:
:undoc-members:
:show-inheritance:
Submodules
----------
thaliawebsite\.api\.services module
-----------------------------------
.. automodule:: thaliawebsite.api.services
:members:
:undoc-members:
:show-inheritance:
......@@ -6,12 +6,12 @@ from html import unescape
from rest_framework import serializers
from rest_framework.fields import empty
from thaliawebsite.api.services import create_image_thumbnail_dict
from events import services
from events.exceptions import RegistrationError
from events.models import Event, Registration, RegistrationInformationField
from pizzas.models import PizzaEvent
from thaliawebsite.settings import settings
from utils.templatetags.thumbnail import thumbnail
class CalenderJSSerializer(serializers.ModelSerializer):
......@@ -244,22 +244,12 @@ class RegistrationListSerializer(serializers.ModelSerializer):
def _avatar(self, instance):
placeholder = self.context['request'].build_absolute_uri(
static('members/images/default-avatar.jpg'))
data = {
'full': placeholder,
'small': placeholder,
'medium': placeholder,
'large': placeholder,
}
file = None
if instance.member and instance.member.profile.photo:
data['full'] = self.context['request'].build_absolute_uri(
'%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
data['small'] = self.context['request'].build_absolute_uri(
thumbnail(instance.member.profile.photo, '110x110', 1))
data['medium'] = self.context['request'].build_absolute_uri(
thumbnail(instance.member.profile.photo, '220x220', 1))
data['large'] = self.context['request'].build_absolute_uri(
thumbnail(instance.member.profile.photo, '800x800', 1))
return data
file = instance.member.profile.photo
return create_image_thumbnail_dict(
self.context['request'], file, placeholder=placeholder,
size_large='800x800')
class RegistrationSerializer(serializers.ModelSerializer):
......@@ -315,22 +305,12 @@ class RegistrationSerializer(serializers.ModelSerializer):
def _avatar(self, instance):
placeholder = self.context['request'].build_absolute_uri(
static('members/images/default-avatar.jpg'))
data = {
'full': placeholder,
'small': placeholder,
'medium': placeholder,
'large': placeholder,
}
file = None
if instance.member and instance.member.profile.photo:
data['full'] = self.context['request'].build_absolute_uri(
'%s%s' % (settings.MEDIA_URL, instance.member.profile.photo))
data['small'] = self.context['request'].build_absolute_uri(
thumbnail(instance.member.profile.photo, '110x110', 1))
data['medium'] = self.context['request'].build_absolute_uri(
thumbnail(instance.member.profile.photo, '220x220', 1))
data['large'] = self.context['request'].build_absolute_uri(
thumbnail(instance.member.profile.photo, '800x800', 1))
return data
file = instance.member.profile.photo
return create_image_thumbnail_dict(
self.context['request'], file, placeholder=placeholder,
size_large='800x800')
def __init__(self, instance=None, data=empty, **kwargs):
super().__init__(instance, data, **kwargs)
......
......@@ -5,10 +5,10 @@ from django.templatetags.static import static
from django.urls import reverse
from rest_framework import serializers
from thaliawebsite.api.services import create_image_thumbnail_dict
from events.api.serializers import CalenderJSSerializer
from members.models import Member
from members.services import member_achievements
from thaliawebsite.settings import settings
from utils.templatetags.thumbnail import thumbnail
......@@ -114,22 +114,12 @@ class MemberRetrieveSerializer(serializers.ModelSerializer):
def _avatar(self, instance):
placeholder = self.context['request'].build_absolute_uri(
static('members/images/default-avatar.jpg'))
data = {
'full': placeholder,
'small': placeholder,
'medium': placeholder,
'large': placeholder,
}
file = None
if instance.profile.photo:
data['full'] = self.context['request'].build_absolute_uri(
'%s%s' % (settings.MEDIA_URL, instance.profile.photo))
data['small'] = self.context['request'].build_absolute_uri(
thumbnail(instance.profile.photo, '110x110', 1))
data['medium'] = self.context['request'].build_absolute_uri(
thumbnail(instance.profile.photo, '220x220', 1))
data['large'] = self.context['request'].build_absolute_uri(
thumbnail(instance.profile.photo, '800x800', 1))
return data
file = instance.profile.photo
return create_image_thumbnail_dict(
self.context['request'], file, placeholder=placeholder,
size_large='800x800')
class MemberListSerializer(serializers.ModelSerializer):
......@@ -154,20 +144,10 @@ class MemberListSerializer(serializers.ModelSerializer):
def _avatar(self, instance):
placeholder = self.context['request'].build_absolute_uri(
static('members/images/default-avatar.jpg'))
data = {
'full': placeholder,
'small': placeholder,
'medium': placeholder,
'large': placeholder,
}
static('members/images/default-avatar.jpg'))
file = None
if instance.profile.photo:
data['full'] = self.context['request'].build_absolute_uri(
'%s%s' % (settings.MEDIA_URL, instance.profile.photo))
data['small'] = self.context['request'].build_absolute_uri(
thumbnail(instance.profile.photo, '110x110', 1))
data['medium'] = self.context['request'].build_absolute_uri(
thumbnail(instance.profile.photo, '220x220', 1))
data['large'] = self.context['request'].build_absolute_uri(
thumbnail(instance.profile.photo, '800x800', 1))
return data
file = instance.profile.photo
return create_image_thumbnail_dict(
self.context['request'], file, placeholder=placeholder,
size_large='800x800')
from rest_framework import serializers
from thaliawebsite.api.services import create_image_thumbnail_dict
from photos import services
from photos.models import Photo, Album
class PhotoRetrieveSerializer(serializers.ModelSerializer):
file = serializers.SerializerMethodField('_file')
def _file(self, obj):
file = None
if obj:
file = obj.file
return create_image_thumbnail_dict(
self.context['request'], file)
class Meta:
model = Photo
fields = ('pk', 'rotation', 'hidden', 'album', 'file')
class PhotoCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
fields = ('pk', 'rotation', 'hidden', 'album', 'file')
class AlbumSerializer(serializers.ModelSerializer):
photos = serializers.SerializerMethodField('_photos')
accessible = serializers.SerializerMethodField('_accessible')
def _accessible(self, obj):
return services.is_album_accessible(self.context['request'], obj)
def _photos(self, obj):
if self._accessible(obj):
return PhotoRetrieveSerializer(obj.photo_set,
context=self.context,
many=True).data
return []
def create(self, validated_data):
photos_data = validated_data.pop('photos')
album = Album.objects.create(**validated_data)
for photo_data in photos_data:
Photo.objects.create(album=album, **photo_data)
return album
def update(self, instance, validated_data):
photos_data = validated_data.pop('photos')
album = Album.objects.update(**validated_data)
for photo_data in photos_data:
Photo.objects.update(album=album, **photo_data)
return album
class Meta:
model = Album
fields = ('pk', 'title_nl', 'title_en', 'date', 'hidden', 'shareable',
'accessible', 'photos')
class AlbumListSerializer(serializers.ModelSerializer):
cover = PhotoRetrieveSerializer()
accessible = serializers.SerializerMethodField('_accessible')
def _accessible(self, obj):
return services.is_album_accessible(self.context['request'], obj)
class Meta:
model = Album
fields = ('pk', 'title_nl', 'title_en', 'date', 'hidden', 'shareable',
'accessible', 'cover')
from rest_framework import routers
from photos.api import viewsets
router = routers.SimpleRouter()
router.register(r'photos/images', viewsets.PhotosViewSet)
router.register(r'photos/albums', viewsets.AlbumsViewSet)
urlpatterns = router.urls
from rest_framework import permissions
from rest_framework.exceptions import PermissionDenied
from rest_framework.mixins import CreateModelMixin, \
UpdateModelMixin
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from photos import services
from photos.api import serializers
from photos.models import Album, Photo
class AlbumsViewSet(ModelViewSet):
permission_classes = (permissions.IsAuthenticated,)
queryset = Album.objects.all()
def get_queryset(self):
return services.annotate_accessible_albums(self.request,
Album.objects.all())
def create(self, request, *args, **kwargs):
if self.request.user.has_perm('photos.create_album'):
return super().create(request, *args, **kwargs)
raise PermissionDenied
def update(self, request, *args, **kwargs):
if self.request.user.has_perm('photos.change_album'):
return super().update(request, *args, **kwargs)
raise PermissionDenied
def get_serializer_class(self):
if self.action == 'list':
return serializers.AlbumListSerializer
return serializers.AlbumSerializer
class PhotosViewSet(GenericViewSet, CreateModelMixin, UpdateModelMixin):
queryset = Photo.objects.all()
permission_classes = (permissions.IsAuthenticated,)
serializer_class = serializers.PhotoCreateSerializer
def create(self, request, *args, **kwargs):
if self.request.user.has_perm('photos.create_photo'):
return super().create(request, *args, **kwargs)
raise PermissionDenied
def update(self, request, *args, **kwargs):
if self.request.user.has_perm('photos.change_photo'):
return super().update(request, *args, **kwargs)
raise PermissionDenied
from django.db.models import When, Value, BooleanField, ExpressionWrapper, Q, \
Case
def is_album_accessible(request, album):
if request.member and request.member.current_membership is None:
albums_filter = Q(pk__in=[])
for membership in request.member.membership_set.all():
if membership.until is not None:
albums_filter |= (Q(date__gte=membership.since) & Q(
date__lte=membership.until))
else:
albums_filter |= (Q(date__gte=membership.since))
return album.filter(albums_filter).exists()
elif request.member and request.member.current_membership is not None:
return True
return False
# Annotate the albums which are accessible by the user
def annotate_accessible_albums(request, albums):
if request.member and request.member.current_membership is None:
# The user is currently not a member
# so only show photos that were made during their membership
albums_filter = Q(pk__in=[])
for membership in request.member.membership_set.all():
if membership.until is not None:
albums_filter |= (Q(date__gte=membership.since) & Q(
date__lte=membership.until))
else:
albums_filter |= (Q(date__gte=membership.since))
albums = albums.annotate(accessible=Case(
When(albums_filter, then=Value(True)),
default=Value(False),
output_field=BooleanField()))
else:
# The user is currently a member, so show all albums
albums = albums.annotate(accessible=ExpressionWrapper(
Value(True), output_field=BooleanField()))
return albums
def can_view_album(request, album):
if request.member.current_membership is None:
# This user is currently not a member, so need to check if he/she
# can view this album by checking the membership
filter = Q(since__lte=album.date) & (Q(until__gte=album.date) |
Q(until=None))
return request.member.membership_set.filter(filter).count() > 0
return False
import os
from tempfile import gettempdir
from zipfile import ZipFile
from django.core.exceptions import SuspiciousFileOperation
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.exceptions import SuspiciousFileOperation
from django.core.paginator import EmptyPage, Paginator
from django.http import Http404
from django.db.models import (BooleanField, Case, ExpressionWrapper, Q, Value,
When)
from django.shortcuts import get_object_or_404, render
from sendfile import sendfile
from zipfile import ZipFile
from tempfile import gettempdir
from photos import services
from utils.views import _private_thumbnails_unauthed
from .models import Album
COVER_FILENAME = 'cover.jpg'
......@@ -24,26 +22,7 @@ def index(request):
# Only show published albums
albums = Album.objects.filter(hidden=False)
# Annotate the albums which are accessible by the user
if request.member.current_membership is None:
# The user is currently not a member
# so only show photos that were made during their membership
albums_filter = Q(pk__in=[])
for membership in request.member.membership_set.all():
if membership.until is not None:
albums_filter |= (Q(date__gte=membership.since) & Q(
date__lte=membership.until))
else:
albums_filter |= (Q(date__gte=membership.since))
albums = albums.annotate(accessible=Case(
When(albums_filter, then=Value(True)),
default=Value(False),
output_field=BooleanField()))
else:
# The user is currently a member, so show all albums
albums = albums.annotate(accessible=ExpressionWrapper(
Value(True), output_field=BooleanField()))
services.annotate_accessible_albums(request, albums)
albums = albums.order_by('-date')
paginator = Paginator(albums, 12)
......@@ -85,17 +64,7 @@ def _render_album_page(request, album):
@login_required
def album(request, slug):
album = get_object_or_404(Album, slug=slug)
can_view = True
# Check if the user currently has a membership
if request.member.current_membership is None:
# This user is currently not a member, so need to check if he/she
# can view this album by checking the membership
filter = Q(since__lte=album.date) & (Q(until__gte=album.date) |
Q(until=None))
can_view = request.member.membership_set.filter(filter).count() > 0
if can_view:
if services.can_view_album(request, album):
return _render_album_page(request, album)
raise Http404("Sorry, you're not allowed to view this album")
......
from thaliawebsite.settings import settings
from utils.templatetags.thumbnail import thumbnail
def create_image_thumbnail_dict(request, file, placeholder='',
size_small='110x110', size_medium='220x220',
size_large='1024x768'):
if file:
return {
'full': request.build_absolute_uri('{}{}'.format(
settings.MEDIA_URL, file)),
'small': request.build_absolute_uri(thumbnail(
file, size_small, 1)),
'medium': request.build_absolute_uri(thumbnail(
file, size_medium, 1)),
'large': request.build_absolute_uri(thumbnail(
file, size_large, 1))
}
return {
'full': placeholder,
'small': placeholder,
'medium': placeholder,
'large': placeholder,
}
......@@ -105,6 +105,7 @@ urlpatterns = [
url(r'^', include('partners.api.urls')),
url(r'^', include('mailinglists.api.urls')),
url(r'^', include('pizzas.api.urls')),
url(r'^', include('photos.api.urls')),
url(r'^', include('pushnotifications.api.urls')),
])),
])),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment