diff --git a/care/users/reset_password_views.py b/care/users/reset_password_views.py index 89f67ae087..e204ab0719 100644 --- a/care/users/reset_password_views.py +++ b/care/users/reset_password_views.py @@ -208,6 +208,20 @@ def post(self, request, *args, **kwargs): status=status.HTTP_429_TOO_MANY_REQUESTS, ) + if settings.IS_PRODUCTION and ( + not settings.EMAIL_HOST + or not settings.EMAIL_HOST_USER + or not settings.EMAIL_HOST_PASSWORD + ): + raise exceptions.ValidationError( + { + "detail": [ + _( + "There was a problem resetting your password. Please contact the administrator." + ) + ] + } + ) # before we continue, delete all existing expired tokens password_reset_token_validation_time = get_password_reset_token_expiry_time() diff --git a/care/users/tests/test_auth.py b/care/users/tests/test_auth.py index 695e105564..912e5da010 100644 --- a/care/users/tests/test_auth.py +++ b/care/users/tests/test_auth.py @@ -1,5 +1,6 @@ from datetime import timedelta +from django.core import mail from django.test import override_settings from django.utils.timezone import now from django_rest_passwordreset.models import ResetPasswordToken @@ -99,7 +100,7 @@ def test_auth_verify_with_invalid_token(self): self.assertEqual(response.data["detail"], "Token is invalid or expired") -@override_settings(DISABLE_RATELIMIT=True) +@override_settings(DISABLE_RATELIMIT=True, IS_PRODUCTION=False) class TestPasswordReset(TestUtils, APITestCase): @classmethod def setUpTestData(cls) -> None: @@ -118,13 +119,55 @@ def create_reset_password_token( token.save() return token + @override_settings( + EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend", + ) def test_forgot_password_with_valid_input(self): + mail.outbox = [] + response = self.client.post( + "/api/v1/password_reset/", + {"username": self.user.username}, + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual("Password Reset for Care", mail.outbox[0].subject) + self.assertEqual(mail.outbox[0].to, [self.user.email]) + self.assertTrue(ResetPasswordToken.objects.filter(user=self.user).exists()) + self.assertTrue(ResetPasswordToken.objects.filter(user=self.user).exists()) + + @override_settings(IS_PRODUCTION=True) + def test_forgot_password_without_email_configration(self): + response = self.client.post( + "/api/v1/password_reset/", + {"username": self.user.username}, + ) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + response.json()["detail"][0], + "There was a problem resetting your password. Please contact the administrator.", + ) + + @override_settings( + IS_PRODUCTION=True, + EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend", + EMAIL_HOST="dummy.smtp.server", + EMAIL_HOST_USER="dummy-email@example.com", + EMAIL_HOST_PASSWORD="dummy-password", + ) + def test_forgot_password_with_email_configuration(self): + mail.outbox = [] + response = self.client.post( "/api/v1/password_reset/", {"username": self.user.username}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual("Password Reset for Care", mail.outbox[0].subject) + self.assertEqual(mail.outbox[0].to, [self.user.email]) self.assertTrue(ResetPasswordToken.objects.filter(user=self.user).exists()) def test_forgot_password_with_missing_fields(self):