Archived
- backend/ kept as canonical, api/ features merged (EBook, ReadingProgress, ReadingSettings) - frontend/ kept as canonical, web/ pages merged (Library, Reader, AddBook, Auth, Settings) - Added Dockerfiles for backend/ and frontend/ - Updated docker-compose.yml for consolidated services - Updated README, package.json workspaces - api/ and web/ directories removed
103 lines
4.3 KiB
Python
103 lines
4.3 KiB
Python
from typing import Any
|
|
|
|
from django.db.models import QuerySet, Q
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
|
from rest_framework import parsers, permissions, status, viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.filters import OrderingFilter, SearchFilter
|
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
|
from rest_framework.request import Request
|
|
from rest_framework.response import Response
|
|
|
|
from apps.books.models import Book, EBook, ReadingProgress, ReadingSettings
|
|
from apps.books.serializers import (
|
|
BookDetailSerializer, BookListSerializer, BookSerializer,
|
|
EBookDetailSerializer, EBookListSerializer, EBookUploadSerializer,
|
|
ReadingProgressSerializer, ReadingSettingsSerializer,
|
|
)
|
|
|
|
|
|
class BookViewSet(viewsets.ModelViewSet):
|
|
queryset = Book.objects.all()
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
|
filterset_fields = ["author", "genre", "reading_status"]
|
|
search_fields = ["title", "author", "genre"]
|
|
ordering_fields = ["title", "author", "genre", "created_at"]
|
|
ordering = ["title"]
|
|
|
|
def get_serializer_class(self):
|
|
if self.action == "retrieve":
|
|
return BookDetailSerializer
|
|
if self.action == "list":
|
|
return BookListSerializer
|
|
return BookSerializer
|
|
|
|
def get_queryset(self) -> QuerySet[Book]:
|
|
qs = super().get_queryset()
|
|
query = self.request.query_params.get("q", "").strip()
|
|
if query:
|
|
qs = qs.filter(Q(title__icontains=query) | Q(author__icontains=query) | Q(genre__icontains=query))
|
|
return qs
|
|
|
|
@action(detail=False, methods=["get"], permission_classes=[AllowAny])
|
|
def genres(self, request: Request) -> Response:
|
|
genre_list = Book.objects.values_list("genre", flat=True).distinct().order_by("genre")
|
|
return Response([g for g in genre_list if g])
|
|
|
|
@action(detail=False, methods=["get"], permission_classes=[AllowAny])
|
|
def authors(self, request: Request) -> Response:
|
|
author_list = Book.objects.values_list("author", flat=True).distinct().order_by("author")
|
|
return Response([a for a in author_list if a])
|
|
|
|
|
|
class IsEBookOwner(permissions.BasePermission):
|
|
def has_object_permission(self, request: Request, view: object, obj: EBook) -> bool:
|
|
return obj.user == request.user
|
|
|
|
|
|
class EBookViewSet(viewsets.ModelViewSet):
|
|
parser_classes = [parsers.MultiPartParser, parsers.FormParser, parsers.JSONParser]
|
|
permission_classes = [IsAuthenticated, IsEBookOwner]
|
|
|
|
def get_serializer_class(self):
|
|
if self.action == "create":
|
|
return EBookUploadSerializer
|
|
if self.action == "list":
|
|
return EBookListSerializer
|
|
return EBookDetailSerializer
|
|
|
|
def get_queryset(self):
|
|
return EBook.objects.filter(user=self.request.user).select_related("reading_progress", "user")
|
|
|
|
@action(detail=True, methods=["get", "patch"])
|
|
def progress(self, request: Request, pk: int | None = None) -> Response:
|
|
ebook = self.get_object()
|
|
progress_obj, _created = ReadingProgress.objects.get_or_create(user=request.user, ebook=ebook)
|
|
if request.method == "GET":
|
|
serializer = ReadingProgressSerializer(progress_obj)
|
|
return Response(serializer.data)
|
|
serializer = ReadingProgressSerializer(progress_obj, data=request.data, partial=True)
|
|
serializer.is_valid(raise_exception=True)
|
|
serializer.save()
|
|
return Response(serializer.data)
|
|
|
|
|
|
class ReadingSettingsViewSet(viewsets.GenericViewSet):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = ReadingSettingsSerializer
|
|
|
|
def get_queryset(self):
|
|
return ReadingSettings.objects.filter(user=self.request.user)
|
|
|
|
def list(self, request: Request) -> Response:
|
|
settings_obj, _created = ReadingSettings.objects.get_or_create(user=request.user)
|
|
serializer = self.get_serializer(settings_obj)
|
|
return Response(serializer.data)
|
|
|
|
def partial_update(self, request: Request) -> Response:
|
|
settings_obj, _created = ReadingSettings.objects.get_or_create(user=request.user)
|
|
serializer = self.get_serializer(settings_obj, data=request.data, partial=True)
|
|
serializer.is_valid(raise_exception=True)
|
|
serializer.save()
|
|
return Response(serializer.data) |