X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/b74fa4eb15c62d11fe0fa2b1015571c90681dd86..e7d9b3875966262ee2e9eb6c281d2677a05a4e91:/src/social/api/views.py?ds=inline diff --git a/src/social/api/views.py b/src/social/api/views.py index 1be521044..867a05a54 100644 --- a/src/social/api/views.py +++ b/src/social/api/views.py @@ -1,21 +1,24 @@ -# -*- 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 +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 -@vary_on_auth +@never_cache class LikeView(APIView): permission_classes = [IsAuthenticated] @@ -33,10 +36,141 @@ class LikeView(APIView): 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'] @@ -59,3 +193,86 @@ class ShelfView(ListAPIView): 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() +