55from typing import TYPE_CHECKING , Type
66from warnings import filterwarnings
77
8- from django .db .models import Count , Max , Prefetch , Q , Sum
8+ from django .db .models import Count , F , Max , Prefetch , Q , Sum
99from django .utils import timezone as tz
1010
11+ from rest_framework .exceptions import APIException
1112from rest_framework .mixins import (
1213 CreateModelMixin , DestroyModelMixin , ListModelMixin ,
1314 RetrieveModelMixin , UpdateModelMixin
1415)
1516from rest_framework .parsers import MultiPartParser
17+ from rest_framework .response import Response
1618from rest_framework .viewsets import GenericViewSet , ModelViewSet
1719
1820from api .v2 .mixins import CORSMixin
2325from . import filters , models , serializers
2426
2527if TYPE_CHECKING : # pragma: no cover
26- from django .db .models .query import QuerySet
28+ from django .db .models .query import QuerySet # isort:skip
29+ from rest_framework .request import Request # isort:skip
2730
2831# XXX: We are overriding the "Series" schema on purpose.
2932filterwarnings ('ignore' , '^Schema' , module = OpenAPISchema .__base__ .__module__ )
3033
3134
35+ class _LegalException (APIException ):
36+ status_code = 451
37+ default_detail = 'This series is licensed.'
38+ default_code = 'licensed_series'
39+
40+
3241class ArtistViewSet (CORSMixin , ModelViewSet ):
3342 """
3443 API endpoints for artists.
@@ -145,6 +154,13 @@ class SeriesViewSet(CORSMixin, ModelViewSet):
145154 ordering = ('title' ,)
146155 lookup_field = 'slug'
147156
157+ def retrieve (self , request : Request , * args , ** kwargs ) -> Response :
158+ instance = self .get_object ()
159+ if instance .licensed :
160+ raise _LegalException ()
161+ serializer = self .get_serializer (instance )
162+ return Response (serializer .data )
163+
148164 def get_queryset (self ) -> QuerySet :
149165 q = Q (chapters__published__lte = tz .now ())
150166 return models .Series .objects .annotate (
@@ -167,18 +183,24 @@ class CubariViewSet(RetrieveModelMixin, CORSMixin, GenericViewSet):
167183 serializer_class = serializers .CubariSerializer
168184 lookup_field = 'slug'
169185
186+ def retrieve (self , request : Request , * args , ** kwargs ) -> Response :
187+ instance = self .get_object ()
188+ if instance .licensed :
189+ raise _LegalException ()
190+ serializer = self .get_serializer (instance )
191+ return Response (serializer .data )
192+
170193 def get_queryset (self ) -> QuerySet :
171194 pages = models .Page .objects .order_by ('number' )
172195 groups = Group .objects .only ('name' )
173196 chapters = models .Chapter .objects .prefetch_related (
174197 Prefetch ('pages' , queryset = pages ),
175198 Prefetch ('groups' , queryset = groups )
176- ).order_by ('volume' , 'number' ).only (
199+ ).order_by (F ( 'volume' ). asc ( nulls_last = True ) , 'number' ).only (
177200 'title' , 'number' , 'volume' , 'modified' , 'series'
178201 )
179202 return models .Series .objects .defer (
180- 'manager_id' , 'modified' ,
181- 'created' , 'completed' , 'licensed'
203+ 'manager_id' , 'modified' , 'created' , 'completed'
182204 ).prefetch_related (
183205 Prefetch ('authors' ), Prefetch ('artists' ),
184206 Prefetch ('chapters' , queryset = chapters )
0 commit comments