Preserve the weirdness of the API.
[wolnelektury.git] / src / catalogue / api / views.py
1 from django.http import Http404, HttpResponse
2 from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404
3 from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
4 from rest_framework import status
5 from paypal.permissions import IsSubscribed
6 from api.handlers import read_tags
7 from .helpers import books_after, order_books
8 from . import serializers
9 from catalogue.models import Book, Collection, Tag, Fragment
10 from catalogue.models.tag import prefetch_relations
11
12
13 class CollectionList(ListAPIView):
14     queryset = Collection.objects.all()
15     serializer_class = serializers.CollectionListSerializer
16
17
18 class CollectionDetail(RetrieveAPIView):
19     queryset = Collection.objects.all()
20     lookup_field = 'slug'
21     serializer_class = serializers.CollectionSerializer
22
23
24 class BookList(ListAPIView):
25     permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
26     queryset = Book.objects.none()  # Required for DjangoModelPermissions
27     serializer_class = serializers.BookListSerializer
28
29     def get_queryset(self):
30         try:
31             tags, ancestors = read_tags(
32                 self.kwargs.get('tags', ''), self.request,
33                 allowed=('author', 'epoch', 'kind', 'genre')
34             )
35         except ValueError:
36             raise Http404
37
38         new_api = self.request.query_params.get('new_api')
39         after = self.request.query_params.get('after', self.kwargs.get('after'))
40         count = self.request.query_params.get('count', self.kwargs.get('count'))
41
42         if tags:
43             if self.kwargs.get('top_level'):
44                 books = Book.tagged_top_level(tags)
45                 if not books:
46                     raise Http404
47                 return books
48             else:
49                 books = Book.tagged.with_all(tags)
50         else:
51             books = Book.objects.all()
52         books = order_books(books, new_api)
53
54         if self.kwargs.get('top_level'):
55             books = books.filter(parent=None)
56         if self.kwargs.get('audiobooks'):
57             books = books.filter(media__type='mp3').distinct()
58         if self.kwargs.get('daisy'):
59             books = books.filter(media__type='daisy').distinct()
60         if self.kwargs.get('recommended'):
61             books = books.filter(recommended=True)
62         if self.kwargs.get('newest'):
63             books = books.order_by('-created_at')
64
65         if after:
66             books = books_after(books, after, new_api)
67
68         prefetch_relations(books, 'author')
69         prefetch_relations(books, 'genre')
70         prefetch_relations(books, 'kind')
71         prefetch_relations(books, 'epoch')
72
73         if count:
74             books = books[:count]
75
76         return books
77
78     def post(self, request):
79         # Permission needed.
80         data = json.loads(request.POST.get('data'))
81         form = BookImportForm(data)
82         if form.is_valid():
83             form.save()
84             return Response({}, status=status.HTTP_201_CREATED)
85         else:
86             raise Http404
87
88
89 class BookDetail(RetrieveAPIView):
90     queryset = Book.objects.all()
91     lookup_field = 'slug'
92     serializer_class = serializers.BookDetailSerializer
93
94
95 class Preview(ListAPIView):
96     queryset = Book.objects.filter(preview=True)
97     serializer_class = serializers.BookPreviewSerializer
98
99
100 class EpubView(RetrieveAPIView):
101     queryset = Book.objects.all()
102     lookup_field = 'slug'
103     permission_classes = [IsSubscribed]
104
105     def get(self, *args, **kwargs):
106         return HttpResponse(self.get_object().get_media('epub'))
107
108
109 class TagCategoryView(ListAPIView):
110     serializer_class = serializers.TagSerializer
111
112     def get_queryset(self):
113         category = self.kwargs['category']
114         tags = Tag.objects.filter(category=category).exclude(items=None).order_by('slug')
115         if self.request.query_params.get('book_only') == 'true':
116             tags = tags.filter(for_books=True)
117         if self.request.GET.get('picture_only') == 'true':
118             tags = filter(for_pictures=True)
119
120         after = self.request.query_params.get('after')
121         count = self.request.query_params.get('count')
122         if after:
123             tags = tags.filter(slug__gt=after)
124         if count:
125             tags = tags[:count]
126
127         return tags
128
129
130 class TagView(RetrieveAPIView):
131     serializer_class = serializers.TagDetailSerializer
132
133     def get_object(self):
134         return get_object_or_404(
135             Tag,
136             category=self.kwargs['category'],
137             slug=self.kwargs['slug']
138         )
139
140
141 class FragmentList(ListAPIView):
142     serializer_class = serializers.FragmentSerializer
143
144     def get_queryset(self):
145         try:
146             tags, ancestors = read_tags(
147                 self.kwargs['tags'],
148                 self.request,
149                 allowed={'author', 'epoch', 'kind', 'genre', 'book', 'theme'}
150             )
151         except ValueError:
152             raise Http404
153         return Fragment.tagged.with_all(tags).select_related('book')
154
155
156 class FragmentView(RetrieveAPIView):
157     serializer_class = serializers.FragmentDetailSerializer
158
159     def get_object(self):
160         return get_object_or_404(
161             Fragment,
162             book__slug=self.kwargs['book'],
163             anchor=self.kwargs['anchor']
164         )