You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

232 lines
8.2 KiB

from django.db.models import Count, Q
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.generics import ListAPIView, RetrieveAPIView, CreateAPIView
from rest_framework.filters import SearchFilter
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from apps.library.pagination import NoPagination
from apps.library.models import *
from apps.library.serializers import *
from apps.library.doc import (
book_list_swagger,
book_detail_swagger,
category_list_swagger,
pinned_collection_list_swagger,
middle_collection_list_swagger
)
class CategoryListView(ListAPIView):
"""
API view to list all book categories
"""
serializer_class = CategorySerializer
permission_classes = (IsAuthenticated,)
@category_list_swagger
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def get_queryset(self):
return Category.objects.filter(
status=True
).annotate(
books_count_annotation=Count('related_categories')
).order_by('title')
class PinnedBookCollectionListView(ListAPIView):
"""
API view to list pinned book collections with their top 3 book covers
"""
serializer_class = PinnedBookCollectionSerializer
permission_classes = (IsAuthenticated,)
pagination_class = NoPagination
@pinned_collection_list_swagger
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def get_queryset(self):
return BookCollection.objects.filter(
status=True,
display_position=BookCollection.DisplayPosition.PINNED
).order_by('-order', '-id')
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
categories_count = Category.objects.filter(status=True).count()
from apps.bookmark.models import Bookmark
bookmarks_count = Bookmark.objects.filter(
service=Bookmark.ServiceChoices.LIBRARY,
).count()
downloads_count = BookDownload.objects.all().count()
info = {
"categories_count": categories_count,
"bookmarks_count": bookmarks_count,
"downloads_count": downloads_count
}
data = {
"count": response.data.get("count"),
"next": response.data.get("next"),
"previous": response.data.get("previous"),
"info": info,
"results": response.data.get("results")
}
return Response(data, status=status.HTTP_200_OK)
class BookListView(ListAPIView):
"""
API view to list books with filtering and search capabilities
"""
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
filter_backends = [SearchFilter]
search_fields = ['title', 'summary', 'author']
@book_list_swagger
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def get_queryset(self):
queryset = Book.objects.filter(status=True)
# Filter by collection if provided
collection_id = self.request.query_params.get('collection_id')
if collection_id:
queryset = queryset.filter(collections__id=collection_id)
# Filter by middle collection if requested
# if self.request.query_params.get('middle'):
# middle_collections = BookCollection.objects.filter(
# status=True,
# display_position=BookCollection.DisplayPosition.MIDDLE
# )
# if middle_collections.exists():
# queryset = queryset.filter(collections__in=middle_collections)
# Filter by bottom collection if requested
# if self.request.query_params.get('bottom'):
# bottom_collections = BookCollection.objects.filter(
# status=True,
# display_position=BookCollection.DisplayPosition.BOTTOM
# )
# if bottom_collections.exists():
# queryset = queryset.filter(collections__in=bottom_collections)
# Filter by bookmarked books if requested
is_bookmark = self.request.query_params.get('is_bookmark', '').lower()
if is_bookmark == 'true':
# Import Bookmark model here to avoid circular imports
from apps.bookmark.models import Bookmark
# Get all bookmarked book IDs for the current user
bookmarked_ids = Bookmark.objects.filter(
user=self.request.user,
service=Bookmark.ServiceChoices.LIBRARY,
status=True
).values_list('content_id', flat=True)
# Filter books by these IDs
queryset = queryset.filter(id__in=bookmarked_ids)
return queryset.order_by('-pin', '-created_at')
class BookDetailView(RetrieveAPIView):
"""
API view to retrieve detailed information about a specific book
"""
serializer_class = BookSerializer
permission_classes = (IsAuthenticated,)
queryset = Book.objects.filter(status=True)
@book_detail_swagger
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
# Increment view count when book details are viewed
instance.increment_view_count()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class MiddleBookCollectionListView(ListAPIView):
"""
API view to list middle section book collections with their books
"""
serializer_class = MiddleBookCollectionSerializer
permission_classes = (IsAuthenticated,)
pagination_class = NoPagination
@middle_collection_list_swagger
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def get_queryset(self):
return BookCollection.objects.filter(
status=True,
display_position=BookCollection.DisplayPosition.MIDDLE
).order_by('order')
class BookDownloadCreateAPIView(CreateAPIView):
"""
API view to create a book download record and increment the book's download count
"""
serializer_class = BookDownloadSerializer
permission_classes = (IsAuthenticated,)
@swagger_auto_schema(
operation_id="download_book",
operation_description="""
Create a book download record and increment the book's download count.
This endpoint creates a record of a book download by the current user and increments
the book's download count. It requires the book ID in the request body.
If the user has already downloaded the book, the existing record will be updated
with the current timestamp.
""",
operation_summary="Download Book",
tags=["Library"],
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'book_id': openapi.Schema(
type=openapi.TYPE_INTEGER,
description="ID of the book to download"
)
},
required=['book_id']
),
responses={
201: openapi.Response(
description="Book download record created successfully",
schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'id': openapi.Schema(type=openapi.TYPE_INTEGER),
'created_at': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME),
'updated_at': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME),
'status': openapi.Schema(type=openapi.TYPE_BOOLEAN)
}
)
),
400: "Invalid request data or book not found",
401: "Authentication credentials were not provided or are invalid",
500: "Internal server error occurred"
}
)
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)