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.
5 from django.contrib.auth.decorators import login_required
6 from django import forms
7 from django.http import HttpResponse
8 from django.http import Http404
9 from django.shortcuts import render
10 from django.views.generic.base import View
11 from oauthlib.common import urlencode
12 from oauthlib.oauth1 import RequestTokenEndpoint, AccessTokenEndpoint
13 from oauthlib.oauth1 import AuthorizationEndpoint, OAuth1Error
14 from api.models import KEY_SIZE, SECRET_SIZE
15 from rest_framework.permissions import IsAuthenticated
16 from rest_framework.response import Response
17 from rest_framework.views import APIView
18 from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404
19 from catalogue.models import Book
20 from .models import BookUserData
21 from . import serializers
22 from .request_validator import PistonRequestValidator
23 from .utils import oauthlib_request, oauthlib_response, vary_on_auth
26 class OAuth1RequestTokenEndpoint(RequestTokenEndpoint):
27 def _create_request(self, *args, **kwargs):
28 r = super(OAuth1RequestTokenEndpoint, self)._create_request(*args, **kwargs)
29 r.redirect_uri = 'oob'
32 def create_request_token(self, request, credentials):
34 'oauth_token': self.token_generator()[:KEY_SIZE],
35 'oauth_token_secret': self.token_generator()[:SECRET_SIZE],
37 token.update(credentials)
38 self.request_validator.save_request_token(token, request)
39 return urlencode(token.items())
43 class OAuth1RequestTokenView(View):
45 self.endpoint = OAuth1RequestTokenEndpoint(PistonRequestValidator())
47 def dispatch(self, request):
48 return oauthlib_response(
49 self.endpoint.create_request_token_response(
50 **oauthlib_request(request)
55 class OAuthAuthenticationForm(forms.Form):
56 oauth_token = forms.CharField(widget=forms.HiddenInput)
57 oauth_callback = forms.CharField(widget=forms.HiddenInput) # changed from URLField - too strict
58 # removed authorize_access - redundant
61 class OAuth1AuthorizationEndpoint(AuthorizationEndpoint):
62 def create_verifier(self, request, credentials):
63 verifier = super(OAuth1AuthorizationEndpoint, self).create_verifier(request, credentials)
65 'oauth_token': verifier['oauth_token'],
70 def oauth_user_auth(request):
71 endpoint = OAuth1AuthorizationEndpoint(PistonRequestValidator())
73 if request.method == "GET":
74 # Why not just get oauth_token here?
75 # This is fairly straightforward, in't?
77 realms, credentials = endpoint.get_realms_and_credentials(
78 **oauthlib_request(request))
79 except OAuth1Error as e:
80 return HttpResponse(e.message, status=400)
81 callback = request.GET.get('oauth_callback')
83 form = OAuthAuthenticationForm(initial={
84 'oauth_token': credentials['resource_owner_key'],
85 'oauth_callback': callback,
88 return render(request, 'oauth/authorize_token.html', {'form': form})
90 elif request.method == "POST":
92 response = oauthlib_response(
93 endpoint.create_authorization_response(
94 credentials={"user": request.user},
95 **oauthlib_request(request)
98 except OAuth1Error as e:
99 return HttpResponse(e.message, status=400)
104 class OAuth1AccessTokenEndpoint(AccessTokenEndpoint):
105 def _create_request(self, *args, **kwargs):
106 r = super(OAuth1AccessTokenEndpoint, self)._create_request(*args, **kwargs)
107 r.verifier = 'x' * 20
110 def create_access_token(self, request, credentials):
111 request.realms = self.request_validator.get_realms(
112 request.resource_owner_key, request)
114 'oauth_token': self.token_generator()[:KEY_SIZE],
115 'oauth_token_secret': self.token_generator()[:SECRET_SIZE],
116 'oauth_authorized_realms': ' '.join(request.realms)
118 token.update(credentials)
119 self.request_validator.save_access_token(token, request)
120 return urlencode(token.items())
124 class OAuth1AccessTokenView(View):
126 self.endpoint = OAuth1AccessTokenEndpoint(PistonRequestValidator())
128 def dispatch(self, request):
129 return oauthlib_response(
130 self.endpoint.create_access_token_response(
131 **oauthlib_request(request)
137 class UserView(RetrieveAPIView):
138 permission_classes = [IsAuthenticated]
139 serializer_class = serializers.UserSerializer
141 def get_object(self):
142 return self.request.user
146 class BookUserDataView(RetrieveAPIView):
147 permission_classes = [IsAuthenticated]
148 serializer_class = serializers.BookUserDataSerializer
149 lookup_field = 'book__slug'
150 lookup_url_kwarg = 'slug'
152 def get_queryset(self):
153 return BookUserData.objects.filter(user=self.request.user)
155 def get(self, *args, **kwargs):
157 return super(BookUserDataView, self).get(*args, **kwargs)
159 return Response({"state": "not_started"})
161 def post(self, request, slug, state):
162 if state not in ('reading', 'complete'):
165 book = get_object_or_404(Book, slug=slug)
166 instance = BookUserData.update(book, request.user, state)
167 serializer = self.get_serializer(instance)
168 return Response(serializer.data)
171 class BlogView(APIView):
172 def get(self, request):