From f12401cee1b73760670be1c6d0da2bf302b6a9f8 Mon Sep 17 00:00:00 2001 From: Ernest Sarfo Date: Wed, 19 Jun 2024 09:23:58 +0000 Subject: [PATCH 1/4] test: password reset with invalid email --- backend/authentication/tests.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/authentication/tests.py b/backend/authentication/tests.py index 4d957ed40..9cdcae1b4 100644 --- a/backend/authentication/tests.py +++ b/backend/authentication/tests.py @@ -210,15 +210,24 @@ def test_pwreset(client: Client) -> None: Scenarios: 1. Password reset email is sent successfully + 2. Password reset with invalid email """ # Setup - plaintext_password = "Activist@123!?" - user = UserFactory(plaintext_password=plaintext_password) + faker = Faker() + new_password = "Activist@123!?" # 1. User exists and password reset is successful + user = UserFactory() response = client.get( path="/v1/auth/pwreset/", data={"email": user.email}, ) assert response.status_code == 200 assert len(mail.outbox) == 1 + + # 2. Password reset with invalid email + response = client.get( + path="/v1/auth/pwreset/", + data={"email": "invalid_email@example.com"} + ) + assert response.status_code == 404 From 94b01c3fad987fb94009bb14c91be12ad9427a0e Mon Sep 17 00:00:00 2001 From: Ernest Sarfo Date: Wed, 19 Jun 2024 09:24:48 +0000 Subject: [PATCH 2/4] test: successful password reset --- backend/authentication/tests.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/authentication/tests.py b/backend/authentication/tests.py index 9cdcae1b4..298d184d2 100644 --- a/backend/authentication/tests.py +++ b/backend/authentication/tests.py @@ -211,6 +211,7 @@ def test_pwreset(client: Client) -> None: Scenarios: 1. Password reset email is sent successfully 2. Password reset with invalid email + 3. Password reset is performed successfully """ # Setup faker = Faker() @@ -231,3 +232,14 @@ def test_pwreset(client: Client) -> None: data={"email": "invalid_email@example.com"} ) assert response.status_code == 404 + + # 3. Password reset is performed successfully + user.verification_code = uuid.uuid4() + user.save() + response = client.post( + path=f"/v1/auth/pwreset/{user.verification_code}/", + data={"password": new_password} + ) + assert response.status_code == 200 + user.refresh_from_db() + assert user.check_password(new_password) From cb07e3bcc6de641a5461ae1fac1311e7ca27075a Mon Sep 17 00:00:00 2001 From: Ernest Sarfo Date: Wed, 19 Jun 2024 09:25:42 +0000 Subject: [PATCH 3/4] test: password reset with invalid verification code --- backend/authentication/tests.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/authentication/tests.py b/backend/authentication/tests.py index 298d184d2..87bdcd0b8 100644 --- a/backend/authentication/tests.py +++ b/backend/authentication/tests.py @@ -212,6 +212,7 @@ def test_pwreset(client: Client) -> None: 1. Password reset email is sent successfully 2. Password reset with invalid email 3. Password reset is performed successfully + 4. Password reset with invalid verification code """ # Setup faker = Faker() @@ -243,3 +244,10 @@ def test_pwreset(client: Client) -> None: assert response.status_code == 200 user.refresh_from_db() assert user.check_password(new_password) + + # 4. Password reset with invalid verification code + response = client.post( + path="/v1/auth/pwreset/invalid_code/", + data={"password": new_password}, + ) + assert response.status_code == 404 From 7169d1a6f89f3b74d21ab01b1e6254758eb224e4 Mon Sep 17 00:00:00 2001 From: tosta Date: Sun, 23 Jun 2024 19:36:14 +0200 Subject: [PATCH 4/4] minor fixes on the pwreset test and fixed pwreset view and serializer --- backend/authentication/factories.py | 2 +- backend/authentication/serializers.py | 8 ++++++-- backend/authentication/tests.py | 14 +++++++------- backend/authentication/views.py | 8 ++++++-- backend/entities/models.py | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/backend/authentication/factories.py b/backend/authentication/factories.py index f93309a1d..2977a91cb 100644 --- a/backend/authentication/factories.py +++ b/backend/authentication/factories.py @@ -39,7 +39,7 @@ class Meta: description = factory.Faker("text", max_nb_chars=500) verified = factory.Faker("boolean") verification_method = factory.Faker("word") - verification_code = factory.Faker("uuid4") + verifictaion_code = factory.Faker("uuid4") email = factory.Faker("email") social_links = factory.List([factory.Faker("user_name") for _ in range(3)]) is_private = factory.Faker("boolean") diff --git a/backend/authentication/serializers.py b/backend/authentication/serializers.py index 1afc26abc..1cbc6f86d 100644 --- a/backend/authentication/serializers.py +++ b/backend/authentication/serializers.py @@ -177,11 +177,15 @@ def validate(self, data: Dict[str, Union[str, Any]]) -> Dict[str, Union[str, Any class PasswordResetSerializer(serializers.Serializer[UserModel]): - email = serializers.EmailField() + email = serializers.EmailField(required=False) password = serializers.CharField(write_only=True) + code = serializers.UUIDField(required=False) def validate(self, data: Dict[str, Union[str, Any]]) -> UserModel: - user = UserModel.objects.filter(email=data.get("email")).first() + if data.get("code") is not None: + user = UserModel.objects.filter(verifictaion_code=data.get("code")).first() + else: + user = UserModel.objects.filter(email=data.get("email")).first() if user is None: raise serializers.ValidationError( diff --git a/backend/authentication/tests.py b/backend/authentication/tests.py index 87bdcd0b8..ebfae4e22 100644 --- a/backend/authentication/tests.py +++ b/backend/authentication/tests.py @@ -21,6 +21,7 @@ from .models import UserModel from django.test import Client from uuid import UUID +import uuid @pytest.mark.django_db @@ -215,11 +216,11 @@ def test_pwreset(client: Client) -> None: 4. Password reset with invalid verification code """ # Setup - faker = Faker() + old_password = "password123!?" new_password = "Activist@123!?" # 1. User exists and password reset is successful - user = UserFactory() + user = UserFactory(plaintext_password=old_password) response = client.get( path="/v1/auth/pwreset/", data={"email": user.email}, @@ -229,17 +230,16 @@ def test_pwreset(client: Client) -> None: # 2. Password reset with invalid email response = client.get( - path="/v1/auth/pwreset/", - data={"email": "invalid_email@example.com"} + path="/v1/auth/pwreset/", data={"email": "invalid_email@example.com"} ) assert response.status_code == 404 # 3. Password reset is performed successfully - user.verification_code = uuid.uuid4() + user.verifictaion_code = uuid.uuid4() user.save() response = client.post( - path=f"/v1/auth/pwreset/{user.verification_code}/", - data={"password": new_password} + path=f"/v1/auth/pwreset/?code={user.verifictaion_code}", + data={"password": new_password}, ) assert response.status_code == 200 user.refresh_from_db() diff --git a/backend/authentication/views.py b/backend/authentication/views.py index caacec8e9..44e1e75ee 100644 --- a/backend/authentication/views.py +++ b/backend/authentication/views.py @@ -209,10 +209,14 @@ def get(self, request: Request) -> Response: ) def post(self, request: Request) -> Response: - serializer = PasswordResetSerializer(data=request.data) + data = { + "password": request.data.get("password"), + "code": request.query_params.get("code"), + } + serializer = PasswordResetSerializer(data=data) serializer.is_valid(raise_exception=True) - user = serializer.validated_data + user: UserModel = serializer.validated_data user.set_password(request.data.get("password")) user.save() diff --git a/backend/entities/models.py b/backend/entities/models.py index 1ba8f41e1..67a1be7c0 100644 --- a/backend/entities/models.py +++ b/backend/entities/models.py @@ -31,7 +31,7 @@ class Organization(models.Model): status = models.ForeignKey( "StatusType", on_delete=models.CASCADE, - default=StatusTypes.PENDING, + default=StatusTypes.PENDING.value, blank=True, null=True, )