Move API models to api app.
[wolnelektury.git] / src / api / views.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 from django.http import Http404
6 from django.views.generic.base import View
7 from oauthlib.common import urlencode
8 from oauthlib.oauth1 import RequestTokenEndpoint, AccessTokenEndpoint
9 from api.models import KEY_SIZE, SECRET_SIZE
10 from rest_framework.permissions import IsAuthenticated
11 from rest_framework.response import Response
12 from rest_framework.views import APIView
13 from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404
14 from migdal.models import Entry
15 from catalogue.models import Book
16 from .models import BookUserData
17 from . import serializers
18 from .request_validator import PistonRequestValidator
19 from .utils import oauthlib_request, oauthlib_response, vary_on_auth
20
21
22 class OAuth1RequestTokenEndpoint(RequestTokenEndpoint):
23     def _create_request(self, *args, **kwargs):
24         r = super(OAuth1RequestTokenEndpoint, self)._create_request(*args, **kwargs)
25         r.redirect_uri = 'oob'
26         return r
27
28     def create_request_token(self, request, credentials):
29         token = {
30             'oauth_token': self.token_generator()[:KEY_SIZE],
31             'oauth_token_secret': self.token_generator()[:SECRET_SIZE],
32         }
33         token.update(credentials)
34         self.request_validator.save_request_token(token, request)
35         return urlencode(token.items())
36
37
38 # Never Cache
39 class OAuth1RequestTokenView(View):
40     def __init__(self):
41         self.endpoint = OAuth1RequestTokenEndpoint(PistonRequestValidator())
42
43     def dispatch(self, request):
44         return oauthlib_response(
45             self.endpoint.create_request_token_response(
46                 **oauthlib_request(request)
47             )
48         )
49
50
51 class OAuth1AccessTokenEndpoint(AccessTokenEndpoint):
52     def _create_request(self, *args, **kwargs):
53         r = super(OAuth1AccessTokenEndpoint, self)._create_request(*args, **kwargs)
54         r.verifier = 'x' * 20
55         return r
56
57     def create_access_token(self, request, credentials):
58         request.realms = self.request_validator.get_realms(
59             request.resource_owner_key, request)
60         token = {
61             'oauth_token': self.token_generator()[:KEY_SIZE],
62             'oauth_token_secret': self.token_generator()[:SECRET_SIZE],
63             'oauth_authorized_realms': ' '.join(request.realms)
64         }
65         token.update(credentials)
66         self.request_validator.save_access_token(token, request)
67         return urlencode(token.items())
68
69
70 # Never cache
71 class OAuth1AccessTokenView(View):
72     def __init__(self):
73         self.endpoint = OAuth1AccessTokenEndpoint(PistonRequestValidator())
74
75     def dispatch(self, request):
76         return oauthlib_response(
77             self.endpoint.create_access_token_response(
78                 **oauthlib_request(request)
79             )
80         )
81
82
83 @vary_on_auth
84 class UserView(RetrieveAPIView):
85     permission_classes = [IsAuthenticated]
86     serializer_class = serializers.UserSerializer
87
88     def get_object(self):
89         return self.request.user
90
91
92 @vary_on_auth
93 class BookUserDataView(RetrieveAPIView):
94     permission_classes = [IsAuthenticated]
95     serializer_class = serializers.BookUserDataSerializer
96     lookup_field = 'book__slug'
97     lookup_url_kwarg = 'slug'
98
99     def get_queryset(self):
100         return BookUserData.objects.filter(user=self.request.user)
101
102     def get(self, *args, **kwargs):
103         try:
104             return super(BookUserDataView, self).get(*args, **kwargs)
105         except Http404:
106             return Response({"state": "not_started"})
107
108     def post(self, request, slug, state):
109         if state not in ('reading', 'complete'):
110             raise Http404
111
112         book = get_object_or_404(Book, slug=slug)
113         instance = BookUserData.update(book, request.user, state)
114         serializer = self.get_serializer(instance)
115         return Response(serializer.data)
116
117
118 class BlogView(ListAPIView):
119     serializer_class = serializers.BlogSerializer
120
121     def get_queryset(self):
122         after = self.request.query_params.get('after')
123         count = int(self.request.query_params.get('count', 20))
124         entries = Entry.published_objects.filter(in_stream=True).order_by('-first_published_at')
125         if after:
126             entries = entries.filter(first_published_at__lt=after)
127         if count:
128             entries = entries[:count]
129         return entries