added user reset password api

This commit is contained in:
Alexander Karpov 2023-09-10 17:38:47 +03:00
parent b59c8fbf8b
commit 3ef20b5eb9
5 changed files with 82 additions and 16 deletions

View File

@ -57,3 +57,24 @@ class Meta:
"is_staff": {"read_only": True},
"is_superuser": {"read_only": True},
}
class UserUpdatePassword(serializers.ModelSerializer):
old_password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ("old_password", "password")
extra_kwargs = {
"password": {"write_only": True},
}
def validate_old_password(self, password: str):
if not self.instance.check_password(password):
raise serializers.ValidationError("Old password is incorrect")
return password
def update(self, instance, validated_data):
instance.set_password(validated_data["password"])
instance.save(update_fields=["password"])
return instance

View File

@ -1,30 +1,36 @@
from django.urls import path
from .views import (
UserListViewSet,
UserRetireUpdateSelfViewSet,
UserRetrieveIdViewSet,
UserRetrieveViewSet,
UserListAPIViewSet,
UserRetireUpdateSelfAPIViewSet,
UserRetrieveAPIViewSet,
UserRetrieveIdAPIAPIView,
UserUpdatePasswordAPIView,
)
app_name = "users_api"
urlpatterns = [
path("", UserListViewSet.as_view(), name="list"),
path("", UserListAPIViewSet.as_view(), name="list"),
path(
"self/",
UserRetireUpdateSelfViewSet.as_view(),
UserRetireUpdateSelfAPIViewSet.as_view(),
name="self",
),
path(
"self/password",
UserUpdatePasswordAPIView.as_view(),
name="password",
),
path(
"id/<int:pk>",
UserRetrieveIdViewSet.as_view(),
UserRetrieveIdAPIAPIView.as_view(),
name="get_by_id",
),
path(
"<str:username>",
UserRetrieveViewSet.as_view(),
UserRetrieveAPIViewSet.as_view(),
name="get",
),
]

View File

@ -9,11 +9,12 @@
UserFullSerializer,
UserPublicInfoSerializer,
UserRegisterSerializer,
UserUpdatePassword,
)
from akarpov.users.models import User
class UserRegisterViewSet(generics.CreateAPIView):
class UserRegisterAPIViewSet(generics.CreateAPIView):
"""Creates new user and sends verification email"""
serializer_class = UserRegisterSerializer
@ -26,7 +27,7 @@ def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class UserEmailValidationViewSet(views.APIView):
class UserEmailValidationAPIViewSet(views.APIView):
"""Receives token from email and activates user"""
permission_classes = [permissions.AllowAny]
@ -43,7 +44,7 @@ def post(self, request):
return Response(status=status.HTTP_200_OK)
class UserListViewSet(generics.ListAPIView):
class UserListAPIViewSet(generics.ListAPIView):
serializer_class = UserPublicInfoSerializer
pagination_class = SmallResultsSetPagination
@ -54,7 +55,7 @@ def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class UserRetrieveViewSet(generics.RetrieveAPIView):
class UserRetrieveAPIViewSet(generics.RetrieveAPIView):
"""Returns user's instance on username"""
serializer_class = UserFullPublicInfoSerializer
@ -70,7 +71,7 @@ def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
class UserRetrieveIdViewSet(UserRetrieveViewSet):
class UserRetrieveIdAPIAPIView(UserRetrieveAPIViewSet):
"""Returns user's instance on user's id"""
lookup_field = "pk"
@ -82,8 +83,15 @@ def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
class UserRetireUpdateSelfViewSet(generics.RetrieveUpdateDestroyAPIView):
class UserRetireUpdateSelfAPIViewSet(generics.RetrieveUpdateDestroyAPIView):
serializer_class = UserFullSerializer
def get_object(self):
return self.request.user
class UserUpdatePasswordAPIView(generics.UpdateAPIView):
serializer_class = UserUpdatePassword
def get_object(self):
return self.request.user

View File

@ -0,0 +1,29 @@
from django.urls import reverse_lazy
from pytest_lambda import lambda_fixture, static_fixture
from rest_framework import status
class TestChangePassword:
url = static_fixture(reverse_lazy("api:users:password"))
new_password = static_fixture("P@ssw0rd123")
user = lambda_fixture(lambda user_factory: user_factory(password="P@ssw0rd"))
def test_ok(self, api_user_client, url, new_password, user):
response = api_user_client.put(
url, {"old_password": "P@ssw0rd", "password": new_password}
)
assert response.status_code == status.HTTP_200_OK
user.refresh_from_db()
assert user.check_password(new_password)
def test_return_err_if_data_is_invalid(
self, api_user_client, url, new_password, user
):
response = api_user_client.put(
url, {"old_password": "123456", "password": new_password}
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
user.refresh_from_db()
assert not user.check_password(new_password)

View File

@ -1,7 +1,7 @@
from django.urls import include, path
from rest_framework.authtoken.views import obtain_auth_token
from akarpov.users.api.views import UserRegisterViewSet
from akarpov.users.api.views import UserRegisterAPIViewSet
app_name = "api"
@ -11,7 +11,9 @@
include(
[
path(
"register/", UserRegisterViewSet.as_view(), name="user_register_api"
"register/",
UserRegisterAPIViewSet.as_view(),
name="user_register_api",
),
path("token/", obtain_auth_token),
]