-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from khodealib/feat/implement-user-auth-views
Feat/implement user auth views
- Loading branch information
Showing
16 changed files
with
282 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from django.core.exceptions import ValidationError | ||
from rest_framework import serializers, status | ||
|
||
from accounts.models import User | ||
|
||
|
||
class UserRegistarionSerializer(serializers.ModelSerializer): | ||
first_name = serializers.CharField(required=False, max_length=255) | ||
last_name = serializers.CharField(required=False, max_length=255) | ||
password = serializers.CharField(write_only=True) | ||
|
||
class Meta: | ||
model = User | ||
fields = ( | ||
"id", | ||
"email", | ||
"first_name", | ||
"last_name", | ||
"password", | ||
) | ||
read_only_fields = ("id",) | ||
|
||
def create(self, validated_data): | ||
try: | ||
user = User.objects.create_user(**validated_data) | ||
except ValidationError as e: | ||
raise serializers.ValidationError( | ||
detail=e.messages, code=status.HTTP_400_BAD_REQUEST | ||
) | ||
return user | ||
|
||
|
||
class UserChangePasswordSerializer(serializers.Serializer): | ||
old_password = serializers.CharField(write_only=True) | ||
new_password = serializers.CharField(write_only=True) | ||
confirm_password = serializers.CharField(write_only=True) | ||
|
||
def validate(self, data): | ||
if data["new_password"] != data["confirm_password"]: | ||
raise serializers.ValidationError( | ||
{"confirm_password": ["Passwords do not match."]}, | ||
code=status.HTTP_400_BAD_REQUEST, | ||
) | ||
return data | ||
|
||
def update(self, instance, validated_data): | ||
instance.set_password(validated_data["new_password"]) | ||
instance.save() | ||
return instance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from .user_model_tests import * | ||
from .jwt_views_tests import * | ||
from .register_view_tests import * | ||
from .change_password_view_tests import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from rest_framework.test import APIClient, APITestCase | ||
|
||
|
||
class UserChangePasswordTest(APITestCase): | ||
def setUp(self): | ||
self.client = APIClient() | ||
self.user = self.client.post( | ||
"/accounts/register/", | ||
{ | ||
"email": "[email protected]", | ||
"password": "Admin@12345678", | ||
"first_name": "Test", | ||
"last_name": "Test", | ||
}, | ||
format="json", | ||
) | ||
self.token = self.client.post( | ||
"/accounts/token/", | ||
{"email": "[email protected]", "password": "Admin@12345678"}, | ||
format="json", | ||
).json()["access"] | ||
|
||
def test_change_password(self): | ||
data = { | ||
"old_password": "Admin@12345678", | ||
"new_password": "Admin@12345679", | ||
"confirm_password": "Admin@12345679", | ||
} | ||
response = self.client.patch( | ||
"/accounts/change-password/", | ||
data, | ||
format="json", | ||
HTTP_AUTHORIZATION="Bearer " + self.token, | ||
) | ||
self.assertEqual(response.status_code, 200) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from rest_framework.test import APIClient, APITestCase | ||
|
||
from accounts.models import User | ||
|
||
|
||
class UserJWTViewsTest(APITestCase): | ||
def setUp(self): | ||
self.client = APIClient() | ||
self.user = User.objects.create_user( | ||
email="[email protected]", | ||
password="Admin@12345678", | ||
first_name="Test", | ||
last_name="Test", | ||
) | ||
|
||
def test_obtain_token(self): | ||
data = {"email": "[email protected]", "password": "Admin@12345678"} | ||
response = self.client.post("/accounts/token/", data, format="json") | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn("access", response.data) | ||
self.assertIn("refresh", response.data) | ||
|
||
def test_obtain_token_invalid_credentials(self): | ||
data = {"email": "[email protected]", "password": "wrong_password"} | ||
response = self.client.post("/accounts/token/", data, format="json") | ||
self.assertEqual(response.status_code, 401) | ||
self.assertNotIn("access", response.data) | ||
self.assertNotIn("refresh", response.data) | ||
|
||
def test_verify_token(self): | ||
data = {"email": "[email protected]", "password": "Admin@12345678"} | ||
access_token = self.client.post("/accounts/token/", data, format="json").data.get("access") | ||
data = {"token": access_token} | ||
response = self.client.post("/accounts/token/verify/", data, format="json") | ||
self.assertEqual(response.status_code, 200) | ||
|
||
def test_refresh_token(self): | ||
data = {"email": "[email protected]", "password": "Admin@12345678"} | ||
tokens = self.client.post("/accounts/token/", data, format="json").data | ||
data = {"refresh": tokens.get("refresh")} | ||
response = self.client.post("/accounts/token/refresh/", data, format="json") | ||
self.assertEqual(response.status_code, 200) | ||
self.assertIn("access", response.data) | ||
self.assertNotIn("refresh", response.data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from rest_framework.test import APIClient, APITestCase | ||
|
||
from accounts.models import User | ||
|
||
|
||
class UserRegisterTest(APITestCase): | ||
def setUp(self): | ||
self.client = APIClient() | ||
self.user = User.objects.create_user( | ||
email="[email protected]", | ||
password="Admin@1234567", | ||
first_name="Test", | ||
last_name="Test", | ||
) | ||
|
||
def test_register_user(self): | ||
data = { | ||
"email": "[email protected]", | ||
"password": "Admin@12345678", | ||
"first_name": "Test", | ||
"last_name": "Test", | ||
} | ||
response = self.client.post("/accounts/register/", data) | ||
self.assertEqual(response.status_code, 201) | ||
|
||
def test_register_user_with_existing_email(self): | ||
data = { | ||
"email": "[email protected]", | ||
"password": "Admin@12345678", | ||
"first_name": "Test", | ||
"last_name": "Test", | ||
} | ||
response = self.client.post("/accounts/register/", data) | ||
self.assertEqual(response.status_code, 400) | ||
|
||
def test_register_user_with_short_password(self): | ||
data = { | ||
"email": "[email protected]", | ||
"password": "123", | ||
"first_name": "Test", | ||
"last_name": "Test", | ||
} | ||
response = self.client.post("/accounts/register/", data) | ||
self.assertEqual(response.status_code, 400) | ||
|
||
def test_register_user_with_no_password(self): | ||
data = {"email": "[email protected]", "first_name": "Test", "last_name": "Test"} | ||
response = self.client.post("/accounts/register/", data) | ||
self.assertEqual(response.status_code, 400) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,18 +4,17 @@ | |
from accounts.models import User | ||
|
||
|
||
# Create your tests here. | ||
class UserModelTest(TestCase): | ||
def setUp(self): | ||
self.user = User.objects.create_user( | ||
email="[email protected]", | ||
password="test123", | ||
password="Admin@12345678", | ||
first_name="Test", | ||
last_name="Test", | ||
) | ||
self.superuser = User.objects.create_superuser( | ||
email="[email protected]", | ||
password="admin123", | ||
password="Admin@12345678", | ||
first_name="Admin", | ||
last_name="Admin", | ||
) | ||
|
@@ -33,7 +32,7 @@ def test_user_email_uniqueness(self): | |
with self.assertRaises(IntegrityError): | ||
User.objects.create_user( | ||
email="[email protected]", | ||
password="test123", | ||
password="Admin@12345678", | ||
first_name="Test", | ||
last_name="Test", | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from django.urls import path | ||
from rest_framework_simplejwt.views import ( | ||
TokenObtainPairView, | ||
TokenRefreshView, | ||
TokenVerifyView, | ||
) | ||
|
||
from accounts.views import UserChangePasswordView, UserRegisterView | ||
|
||
app_name = "accounts" | ||
urlpatterns = [ | ||
path("register/", UserRegisterView.as_view(), name="register"), | ||
path("change-password/", UserChangePasswordView.as_view(), name="change_password"), | ||
# JWT authentication endpoints | ||
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), | ||
path("token/verify/", TokenVerifyView.as_view(), name="token_verify"), | ||
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,36 @@ | ||
from django.shortcuts import render | ||
from rest_framework import generics, status | ||
from rest_framework.permissions import IsAuthenticated | ||
from rest_framework.response import Response | ||
|
||
# Create your views here. | ||
from accounts.models import User | ||
from accounts.serializers import UserChangePasswordSerializer, UserRegistarionSerializer | ||
|
||
|
||
class UserRegisterView(generics.CreateAPIView): | ||
"""Register a new user | ||
Args: | ||
UserRegisterView (generics.CreateAPIView): Register a new user. | ||
""" | ||
|
||
serializer_class = UserRegistarionSerializer | ||
queryset = User.objects.all() | ||
|
||
|
||
class UserChangePasswordView(generics.UpdateAPIView): | ||
"""Update user password | ||
Args: | ||
UserChangePasswordView (generics.UpdateAPIView): Update user password. | ||
""" | ||
|
||
permission_classes = (IsAuthenticated,) | ||
serializer_class = UserChangePasswordSerializer | ||
|
||
def update(self, request, *args, **kwargs): | ||
instance = request.user | ||
serializer = self.get_serializer(instance, data=request.data, partial=True) | ||
serializer.is_valid(raise_exception=True) | ||
serializer.update(instance, serializer.validated_data) | ||
return Response(status=status.HTTP_200_OK) | ||
|
Oops, something went wrong.