-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
#
from django.http import Http404
-from rest_framework.generics import ListAPIView, get_object_or_404
-from rest_framework.permissions import IsAuthenticated
+from rest_framework.generics import ListAPIView, ListCreateAPIView, RetrieveAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, DestroyAPIView, get_object_or_404
+from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.response import Response
+from rest_framework import serializers
from rest_framework.views import APIView
from api.models import BookUserData
+from api.utils import vary_on_auth, never_cache
from catalogue.api.helpers import order_books, books_after
from catalogue.api.serializers import BookSerializer
from catalogue.models import Book
-from social.utils import likes
+import catalogue.models
+from social.utils import likes, get_set
+from social.views import get_sets_for_book_ids
+from social import models
+@never_cache
class LikeView(APIView):
permission_classes = [IsAuthenticated]
return Response({})
+@never_cache
+class LikeView2(APIView):
+ permission_classes = [IsAuthenticated]
+
+ def get(self, request, slug):
+ book = get_object_or_404(Book, slug=slug)
+ return Response({"likes": likes(request.user, book)})
+
+ def put(self, request, slug):
+ book = get_object_or_404(Book, slug=slug)
+ book.like(request.user)
+ return Response({"likes": likes(request.user, book)})
+
+ def delete(self, request, slug):
+ book = get_object_or_404(Book, slug=slug)
+ book.unlike(request.user)
+ return Response({"likes": likes(request.user, book)})
+
+
+@never_cache
+class LikesView(APIView):
+ permission_classes = [IsAuthenticated]
+
+ def get(self, request):
+ slugs = request.GET.getlist('slug')
+ books = Book.objects.filter(slug__in=slugs)
+ books = {b.id: b.slug for b in books}
+ ids = books.keys()
+ res = get_sets_for_book_ids(ids, request.user)
+ res = {books[bid]: v for bid, v in res.items()}
+
+ return Response(res)
+
+
+@never_cache
+class MyLikesView(APIView):
+ permission_classes = [IsAuthenticated]
+
+ def get(self, request):
+ ids = catalogue.models.tag.TagRelation.objects.filter(tag__user=request.user).values_list('object_id', flat=True).distinct()
+ books = Book.objects.filter(id__in=ids)
+ books = {b.id: b.slug for b in books}
+ res = get_sets_for_book_ids(ids, request.user)
+ res = {books[bid]: v for bid, v in res.items()}
+
+ res = list(books.values())
+ res.sort()
+ return Response(res)
+
+
+class TaggedBooksField(serializers.Field):
+ def to_representation(self, value):
+ return catalogue.models.Book.tagged.with_all([value]).values_list('slug', flat=True)
+
+ def to_internal_value(self, value):
+ return {'books': catalogue.models.Book.objects.filter(slug__in=value)}
+
+
+class UserListSerializer(serializers.ModelSerializer):
+ books = TaggedBooksField(source='*')
+
+ class Meta:
+ model = catalogue.models.Tag
+ fields = ['name', 'slug', 'books']
+ read_only_fields = ['slug']
+
+ def create(self, validated_data):
+ instance = get_set(validated_data['user'], validated_data['name'])
+ catalogue.models.tag.TagRelation.objects.filter(tag=instance).delete()
+ for book in validated_data['books']:
+ catalogue.models.Tag.objects.add_tag(book, instance)
+ return instance
+
+ def update(self, instance, validated_data):
+ catalogue.models.tag.TagRelation.objects.filter(tag=instance).delete()
+ for book in validated_data['books']:
+ catalogue.models.Tag.objects.add_tag(book, instance)
+ return instance
+
+class UserListBooksSerializer(UserListSerializer):
+ class Meta:
+ model = catalogue.models.Tag
+ fields = ['books']
+
+
+@never_cache
+class ListsView(ListCreateAPIView):
+ permission_classes = [IsAuthenticated]
+ #pagination_class = None
+ serializer_class = UserListSerializer
+
+ def get_queryset(self):
+ return catalogue.models.Tag.objects.filter(user=self.request.user).exclude(name='')
+
+ def perform_create(self, serializer):
+ serializer.save(user=self.request.user)
+
+
+@never_cache
+class ListView(RetrieveUpdateDestroyAPIView):
+ # TODO: check if can modify
+ permission_classes = [IsAuthenticated]
+ serializer_class = UserListSerializer
+
+ def get_object(self):
+ return get_object_or_404(catalogue.models.Tag, slug=self.kwargs['slug'], user=self.request.user)
+
+ def perform_update(self, serializer):
+ serializer.save(user=self.request.user)
+
+ def post(self, request, slug):
+ serializer = UserListBooksSerializer(data=request.data)
+ serializer.is_valid(raise_exception=True)
+ instance = self.get_object()
+ for book in serializer.validated_data['books']:
+ catalogue.models.Tag.objects.add_tag(book, instance)
+ return Response(self.get_serializer(instance).data)
+
+
+@never_cache
+class ListItemView(APIView):
+ permission_classes = [IsAuthenticated]
+
+ def delete(self, request, slug, book):
+ instance = get_object_or_404(catalogue.models.Tag, slug=slug, user=self.request.user)
+ book = get_object_or_404(catalogue.models.Book, slug=book)
+ catalogue.models.Tag.objects.remove_tag(book, instance)
+ return Response(UserListSerializer(instance).data)
+
+
+@vary_on_auth
class ShelfView(ListAPIView):
permission_classes = [IsAuthenticated]
serializer_class = BookSerializer
+ pagination_class = None
def get_queryset(self):
state = self.kwargs['state']
return books
+
+
+class ProgressSerializer(serializers.ModelSerializer):
+ book = serializers.HyperlinkedRelatedField(
+ read_only=True,
+ view_name='catalogue_api_book',
+ lookup_field='slug'
+ )
+ book_slug = serializers.SlugRelatedField(source='book', read_only=True, slug_field='slug')
+
+ class Meta:
+ model = models.Progress
+ fields = ['book', 'book_slug', 'last_mode', 'text_percent',
+ 'text_anchor',
+ 'audio_percent',
+ 'audio_timestamp',
+ 'implicit_text_percent',
+ 'implicit_text_anchor',
+ 'implicit_audio_percent',
+ 'implicit_audio_timestamp',
+ ]
+
+
+class TextProgressSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = models.Progress
+ fields = [
+ 'text_percent',
+ 'text_anchor',
+ ]
+ read_only_fields = ['text_percent']
+
+class AudioProgressSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = models.Progress
+ fields = ['audio_percent', 'audio_timestamp']
+ read_only_fields = ['audio_percent']
+
+
+@never_cache
+class ProgressListView(ListAPIView):
+ permission_classes = [IsAuthenticated]
+ serializer_class = ProgressSerializer
+
+ def get_queryset(self):
+ return models.Progress.objects.filter(user=self.request.user).order_by('-updated_at')
+
+
+class ProgressMixin:
+ def get_object(self):
+ try:
+ return models.Progress.objects.get(user=self.request.user, book__slug=self.kwargs['slug'])
+ except models.Progress.DoesNotExist:
+ book = get_object_or_404(Book, slug=self.kwargs['slug'])
+ return models.Progress(user=self.request.user, book=book)
+
+
+
+@never_cache
+class ProgressView(ProgressMixin, RetrieveAPIView):
+ permission_classes = [IsAuthenticated]
+ serializer_class = ProgressSerializer
+
+
+@never_cache
+class TextProgressView(ProgressMixin, RetrieveUpdateAPIView):
+ permission_classes = [IsAuthenticated]
+ serializer_class = TextProgressSerializer
+
+ def perform_update(self, serializer):
+ serializer.instance.last_mode = 'text'
+ serializer.save()
+
+
+@never_cache
+class AudioProgressView(ProgressMixin, RetrieveUpdateAPIView):
+ permission_classes = [IsAuthenticated]
+ serializer_class = AudioProgressSerializer
+
+ def perform_update(self, serializer):
+ serializer.instance.last_mode = 'audio'
+ serializer.save()
+