From 8a70102bfb979d1115460a32a32155eb6133b493 Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 19:32:28 +0700 Subject: [PATCH 01/11] [RED] Add test for access token endpoint --- backend/main/test_views.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/backend/main/test_views.py b/backend/main/test_views.py index 12bc594..974072a 100644 --- a/backend/main/test_views.py +++ b/backend/main/test_views.py @@ -44,3 +44,20 @@ class RegisterAPITestCase(APITestCase): ], }, response.data) + + +class AccessTokenAPITestCase(APITestCase): + + def setUp(self): + self.creds = { + 'email': 'donald@duckduckgo.org', + 'password': '5up3r_53cu3r', + } + + User.objects.create_user(**self.creds) + + def test_get_access_token(self): + response = self.client.post('/auth/access', data=self.creds) + + self.assertIn('access', response.data) + self.assertNotIn('password', response.data) -- GitLab From f771f3bc3d40f12efdd5fa396e35c7aa358b8c6e Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 19:40:50 +0700 Subject: [PATCH 02/11] [GREEN] Add urlpatterns to AccessTokenView --- backend/main/urls.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/main/urls.py b/backend/main/urls.py index 0351cf2..ad550b3 100644 --- a/backend/main/urls.py +++ b/backend/main/urls.py @@ -1,4 +1,5 @@ from django.urls import path +from rest_framework_authlib.views import AccessTokenView from .views import ( HelloView, @@ -8,4 +9,5 @@ from .views import ( urlpatterns = [ path('hello/', HelloView.as_view()), path('auth/register', RegisterView.as_view()), + path('auth/access', AccessTokenView.as_view()), ] -- GitLab From 0db27dfba0bbb0d6258f26849541a1828464d645 Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 19:57:40 +0700 Subject: [PATCH 03/11] [RED] Change test's path so they have trailing slash --- backend/main/test_views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/main/test_views.py b/backend/main/test_views.py index 974072a..53bb3fe 100644 --- a/backend/main/test_views.py +++ b/backend/main/test_views.py @@ -21,7 +21,7 @@ class RegisterAPITestCase(APITestCase): 'password': '5up3r_53cuer' } - response = self.client.post('/auth/register', data=data) + response = self.client.post('/auth/register/', data=data) user = User.objects.get(email=data['email']) self.assertEqual(user.email, response.data['email']) @@ -32,7 +32,7 @@ class RegisterAPITestCase(APITestCase): 'password': 'scammer' } - response = self.client.post('/auth/register', data=data) + response = self.client.post('/auth/register/', data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertDictEqual( @@ -57,7 +57,7 @@ class AccessTokenAPITestCase(APITestCase): User.objects.create_user(**self.creds) def test_get_access_token(self): - response = self.client.post('/auth/access', data=self.creds) + response = self.client.post('/auth/access/', data=self.creds) self.assertIn('access', response.data) self.assertNotIn('password', response.data) -- GitLab From aa1fa833a88d9f616635be4f522313738f21e9d7 Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 19:58:56 +0700 Subject: [PATCH 04/11] [GREEN] Add trailing slashes to urlpatterns --- backend/main/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/main/urls.py b/backend/main/urls.py index ad550b3..6b95cac 100644 --- a/backend/main/urls.py +++ b/backend/main/urls.py @@ -8,6 +8,6 @@ from .views import ( urlpatterns = [ path('hello/', HelloView.as_view()), - path('auth/register', RegisterView.as_view()), - path('auth/access', AccessTokenView.as_view()), + path('auth/register/', RegisterView.as_view()), + path('auth/access/', AccessTokenView.as_view()), ] -- GitLab From de4f4194aa975392450bf9f2c707a07753cc177e Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 20:01:12 +0700 Subject: [PATCH 05/11] [RED] Add secret view for debugging --- backend/main/tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/main/tests.py b/backend/main/tests.py index 294f733..09aaab1 100644 --- a/backend/main/tests.py +++ b/backend/main/tests.py @@ -16,3 +16,18 @@ class HelloTests(APITestCase): 'body': 'Hello, World!', }, ) + + +class SecretTests(APITestCase): + + def test_get_secret(self): + response = self.client.get('/secret/') + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertDictEqual( + response.data, + { + 'kind': 'debug', + 'body': 'Hello, My Secret Admirer!', + }, + ) -- GitLab From b24d682c6ba1c957353d964b3f5a3303956b64bf Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 20:04:55 +0700 Subject: [PATCH 06/11] [GREEN] Add SecretView --- backend/main/urls.py | 2 ++ backend/main/views.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/backend/main/urls.py b/backend/main/urls.py index 6b95cac..7bd84d9 100644 --- a/backend/main/urls.py +++ b/backend/main/urls.py @@ -4,10 +4,12 @@ from rest_framework_authlib.views import AccessTokenView from .views import ( HelloView, RegisterView, + SecretView, ) urlpatterns = [ path('hello/', HelloView.as_view()), + path('secret/', SecretView.as_view()), path('auth/register/', RegisterView.as_view()), path('auth/access/', AccessTokenView.as_view()), ] diff --git a/backend/main/views.py b/backend/main/views.py index 0d2bd28..b80502c 100644 --- a/backend/main/views.py +++ b/backend/main/views.py @@ -23,6 +23,23 @@ class HelloView(views.APIView): return Response(msg) +class SecretView(generics.GenericAPIView): + """ + View to get a nice secret message. + """ + + def get(self, request, format=None): + """ + Return a secret message. + """ + msg = { + 'kind': 'debug', + 'body': 'Hello, My Secret Admirer!', + } + + return Response(msg) + + class RegisterView(generics.CreateAPIView): """ RegisterView handles email and password registration. -- GitLab From a07051e9229159d1328610518f4a7ae97cc6272d Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 20:12:56 +0700 Subject: [PATCH 07/11] [RED] Change secret view test to require authentication --- backend/main/tests.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/backend/main/tests.py b/backend/main/tests.py index 09aaab1..4df0ba3 100644 --- a/backend/main/tests.py +++ b/backend/main/tests.py @@ -20,14 +20,11 @@ class HelloTests(APITestCase): class SecretTests(APITestCase): - def test_get_secret(self): + def test_get_secret_unauthorized(self): response = self.client.get('/secret/') - self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) self.assertDictEqual( response.data, - { - 'kind': 'debug', - 'body': 'Hello, My Secret Admirer!', - }, + {'detail': 'Authentication credentials were not provided.'}, ) -- GitLab From 7e1463c259bef656a862f8b423d6fc05a060c9f2 Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 20:59:37 +0700 Subject: [PATCH 08/11] [RED] Add tests with authorized access to secret view --- backend/main/tests.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/backend/main/tests.py b/backend/main/tests.py index 4df0ba3..853b3ff 100644 --- a/backend/main/tests.py +++ b/backend/main/tests.py @@ -1,6 +1,8 @@ from rest_framework import status from rest_framework.test import APITestCase +from .models import User + # Create your tests here. class HelloTests(APITestCase): @@ -20,6 +22,14 @@ class HelloTests(APITestCase): class SecretTests(APITestCase): + def setUp(self): + self.creds = { + 'email': 'donald@duckduckgo.org', + 'password': 'quack_quack_qu4ck', + } + + User.objects.create_user(**self.creds) + def test_get_secret_unauthorized(self): response = self.client.get('/secret/') @@ -28,3 +38,22 @@ class SecretTests(APITestCase): response.data, {'detail': 'Authentication credentials were not provided.'}, ) + + def test_get_access_token_and_get_secret(self): + response = self.client.post('/auth/access/', data=self.creds) + + self.assertIn('access', response.data) + access_token = response.data['access'] + + http_authorization = b'Bearer ' + access_token.encode('utf-8') + response = self.client.get('/secret/', + HTTP_AUTHORIZATION=http_authorization) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertDictEqual( + response.data, + { + 'kind': 'debug', + 'body': 'Hello, My Secret Admirer!', + } + ) -- GitLab From c96a65635ad89d7dda06ff3a5c53b3a06ec42cc7 Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 21:04:17 +0700 Subject: [PATCH 09/11] [GREEN] Set authentication and permission for secret --- backend/dblood/settings.py | 8 ++++++++ backend/main/views.py | 2 ++ 2 files changed, 10 insertions(+) diff --git a/backend/dblood/settings.py b/backend/dblood/settings.py index b5278a1..40e7367 100644 --- a/backend/dblood/settings.py +++ b/backend/dblood/settings.py @@ -149,3 +149,11 @@ else: STATIC_URL = os.getenv('STATIC_URL', 'https://dblood-api.netlify.com/') STATIC_ROOT = 'static_root/' + +# REST Framework settings + +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_authlib.authentication.JWTAuthentication', + ) +} diff --git a/backend/main/views.py b/backend/main/views.py index b80502c..b5369ac 100644 --- a/backend/main/views.py +++ b/backend/main/views.py @@ -1,5 +1,6 @@ from rest_framework import generics from rest_framework import views +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from . import serializers @@ -27,6 +28,7 @@ class SecretView(generics.GenericAPIView): """ View to get a nice secret message. """ + permission_classes = [IsAuthenticated] def get(self, request, format=None): """ -- GitLab From 6b9bb38ef8d57327c99e2f0edb952da035b619d7 Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 21:09:02 +0700 Subject: [PATCH 10/11] [RED] Change secret test to return personalized response --- backend/main/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main/tests.py b/backend/main/tests.py index 853b3ff..7e507a4 100644 --- a/backend/main/tests.py +++ b/backend/main/tests.py @@ -54,6 +54,6 @@ class SecretTests(APITestCase): response.data, { 'kind': 'debug', - 'body': 'Hello, My Secret Admirer!', + 'body': f'Hello {self.creds["email"]}, My Secret Admirer!', } ) -- GitLab From 7d206aa7c8c7ac53443d364286ce9617f507a16c Mon Sep 17 00:00:00 2001 From: giovanism Date: Mon, 2 Mar 2020 21:10:54 +0700 Subject: [PATCH 11/11] [GREEN] Change secret view to return personalized response --- backend/main/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main/views.py b/backend/main/views.py index b5369ac..6d49a8c 100644 --- a/backend/main/views.py +++ b/backend/main/views.py @@ -36,7 +36,7 @@ class SecretView(generics.GenericAPIView): """ msg = { 'kind': 'debug', - 'body': 'Hello, My Secret Admirer!', + 'body': f'Hello {request.user.email}, My Secret Admirer!', } return Response(msg) -- GitLab