Source code for reader.api

"""API viewsets for the reader app."""

from typing import TYPE_CHECKING, List
from warnings import filterwarnings

from django.db.models import Count, Max, Q
from django.utils import timezone as tz

from rest_framework.mixins import (
    CreateModelMixin, DestroyModelMixin, ListModelMixin,
    RetrieveModelMixin, UpdateModelMixin
)
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from api.v2.mixins import CORSMixin
from api.v2.pagination import PageLimitPagination
from api.v2.schema import OpenAPISchema

from . import filters, models, serializers

if TYPE_CHECKING:  # pragma: no cover
    from django.db.models.query import QuerySet

# XXX: We are overriding the "Series" schema on purpose.
filterwarnings('ignore', '^Schema', module=OpenAPISchema.__base__.__module__)


[docs]class ArtistViewSet(CORSMixin, ModelViewSet): """ API endpoints for artists. * list: List artists. * read: View a certain artist. * create: Create a new artist. * update: Edit the given artist. * patch: Patch the given artist. * delete: Delete the given artist. """ schema = OpenAPISchema(tags=('artists',)) queryset = models.Artist.objects.all() serializer_class = serializers.ArtistSerializer
[docs]class AuthorViewSet(CORSMixin, ModelViewSet): """ API endpoints for authors. * list: List authors. * read: View a certain author. * create: Create a new author. * update: Edit the given author. * patch: Patch the given author. * delete: Delete the given author. """ schema = OpenAPISchema(tags=('authors',)) queryset = models.Author.objects.all() serializer_class = serializers.AuthorSerializer
[docs]class CategoryViewSet(CORSMixin, ModelViewSet): """ API endpoints for categories. * list: List categories. * read: View a certain category. * create: Create a new category. * patch: Patch the given category. * delete: Delete the given category. """ schema = OpenAPISchema(tags=('categories',), component_name='Category') http_method_names = ('get', 'post', 'patch', 'delete', 'head', 'options') serializer_class = serializers.CategorySerializer queryset = models.Category.objects.all() lookup_field = 'name'
[docs]class PageViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, UpdateModelMixin, CORSMixin, GenericViewSet): """ API endpoints for pages. * list: List a chapter's pages. * create: Create a new page. * update: Edit the given page. * delete: Delete the given page. """ schema = OpenAPISchema(tags=('pages',),) http_method_names = ('get', 'post', 'put', 'delete', 'head', 'options') queryset = models.Page.objects.all() serializer_class = serializers.PageSerializer filter_backends = filters.PAGE_FILTERS
[docs]class ChapterViewSet(CORSMixin, ModelViewSet): """ API endpoints for chapters. * list: List chapters. * read: View a certain chapter. * create: Create a new chapter. * update: Edit the given chapter. * patch: Patch the given chapter. * delete: Delete the given chapter. """ schema = OpenAPISchema(tags=('chapters',)) serializer_class = serializers.ChapterSerializer filter_backends = filters.CHAPTER_FILTERS
[docs] def get_queryset(self) -> 'QuerySet': return models.Chapter.objects.select_related('series') \ .filter(published__lte=tz.now()).order_by('-published')
[docs]class SeriesViewSet(CORSMixin, ModelViewSet): """ API endpoints for series. * list: List or search for series. * read: View the details of a series. * create: Create a new series. * update: Edit the given series. * patch: Patch the given series. * delete: Delete the given series. """ schema = OpenAPISchema( operation_id_base='Series', tags=('series',), component_name='Series' ) filter_backends = filters.SERIES_FILTERS pagination_class = PageLimitPagination ordering = ('title',) lookup_field = 'slug'
[docs] def get_queryset(self) -> 'QuerySet': q = Q(chapters__published__lte=tz.now()) return models.Series.objects.prefetch_related('chapters').annotate( chapter_count=Count('chapters', filter=q), latest_upload=Max('chapters__published') ).filter(chapter_count__gt=0).distinct()
[docs] def get_serializer_class(self) -> serializers.TSerializer: # explicit call until we drop Python 3.6 in v0.8 return serializers.SeriesSerializer.__class_getitem__(self.action)
[docs]class CubariViewSet(RetrieveModelMixin, CORSMixin, GenericViewSet): """ API endpoints for Cubari. * read: Generate JSON for a cubari.moe gist. """ schema = OpenAPISchema(tags=('cubari',), operation_id_base='Cubari') queryset = models.Series.objects.all() serializer_class = serializers.CubariSerializer permission_classes = (IsAdminUser,) lookup_field = 'slug' _restrict = True
[docs] def get_permissions(self) -> List: if self.request.method == 'OPTIONS': return [] return super().get_permissions()
__all__ = [ 'ArtistViewSet', 'AuthorViewSet', 'CategoryViewSet', 'PageViewSet', 'ChapterViewSet', 'SeriesViewSet', 'CubariViewSet' ]