from django.shortcuts import get_object_or_404 from rest_framework import parsers, permissions, status, viewsets from rest_framework.decorators import action from rest_framework.request import Request from rest_framework.response import Response from books.models import Book, ReadingProgress, ReadingSettings from books.serializers import ( BookDetailSerializer, BookListSerializer, BookUploadSerializer, ReadingProgressSerializer, ReadingSettingsSerializer, ) class IsBookOwner(permissions.BasePermission): """Only the owner of a book can access it.""" def has_object_permission( self, request: Request, view: object, obj: Book ) -> bool: return obj.user == request.user class BookViewSet(viewsets.ModelViewSet): """API endpoint for managing user books.""" parser_classes = [parsers.MultiPartParser, parsers.FormParser, parsers.JSONParser] permission_classes = [permissions.IsAuthenticated, IsBookOwner] def get_serializer_class(self) -> type: if self.action == "create": return BookUploadSerializer if self.action == "list": return BookListSerializer return BookDetailSerializer def get_queryset(self): return ( Book.objects.filter(user=self.request.user) .select_related("reading_progress", "user") .prefetch_related() ) @action(detail=True, methods=["get", "patch"]) def progress(self, request: Request, pk: int | None = None) -> Response: """Get or update reading progress for a specific book.""" book = self.get_object() progress, _created = ReadingProgress.objects.get_or_create( user=request.user, book=book, ) if request.method == "GET": serializer = ReadingProgressSerializer(progress) return Response(serializer.data) serializer = ReadingProgressSerializer(progress, data=request.data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) class ReadingSettingsViewSet(viewsets.GenericViewSet): """API endpoint for user reading settings.""" permission_classes = [permissions.IsAuthenticated] serializer_class = ReadingSettingsSerializer def get_queryset(self): return ReadingSettings.objects.filter(user=self.request.user) def list(self, request: Request) -> Response: settings, _created = ReadingSettings.objects.get_or_create( user=request.user, ) serializer = self.get_serializer(settings) return Response(serializer.data) def partial_update(self, request: Request) -> Response: settings, _created = ReadingSettings.objects.get_or_create( user=request.user, ) serializer = self.get_serializer(settings, data=request.data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data)