From 73705d57068ef63eb5c36b104dc25b68fa14dcfd Mon Sep 17 00:00:00 2001 From: Matthew Elwell Date: Tue, 5 Sep 2023 17:07:25 +0100 Subject: [PATCH] fix: allow registration via invite link if ALLOW_REGISTRATION_WITHOUT_INVITE is False (#2731) --- api/custom_auth/oauth/serializers.py | 6 ++-- .../oauth/tests/test_unit_serializers.py | 31 +++++++++++++++++++ api/custom_auth/serializers.py | 3 +- api/custom_auth/tests/test_serializer.py | 30 +++++++++++++++++- 4 files changed, 65 insertions(+), 5 deletions(-) diff --git a/api/custom_auth/oauth/serializers.py b/api/custom_auth/oauth/serializers.py index 3eab90e2d6a6..63e758b127bf 100644 --- a/api/custom_auth/oauth/serializers.py +++ b/api/custom_auth/oauth/serializers.py @@ -57,15 +57,15 @@ def _get_user(self, user_data: dict): existing_user = UserModel.objects.filter(email=email).first() if not existing_user: + sign_up_type = self.validated_data.get("sign_up_type") if not ( settings.ALLOW_REGISTRATION_WITHOUT_INVITE + or sign_up_type == SignUpType.INVITE_LINK.value or Invite.objects.filter(email=email).exists() ): raise PermissionDenied(USER_REGISTRATION_WITHOUT_INVITE_ERROR_MESSAGE) - return UserModel.objects.create( - **user_data, sign_up_type=self.validated_data.get("sign_up_type") - ) + return UserModel.objects.create(**user_data, sign_up_type=sign_up_type) return existing_user diff --git a/api/custom_auth/oauth/tests/test_unit_serializers.py b/api/custom_auth/oauth/tests/test_unit_serializers.py index 6a162e4fc633..7b13a98717a8 100644 --- a/api/custom_auth/oauth/tests/test_unit_serializers.py +++ b/api/custom_auth/oauth/tests/test_unit_serializers.py @@ -4,6 +4,8 @@ from django.contrib.auth import get_user_model from django.test import RequestFactory from django.utils import timezone +from pytest_django.fixtures import SettingsWrapper +from pytest_mock import MockerFixture from rest_framework.authtoken.models import Token from custom_auth.oauth.serializers import ( @@ -11,6 +13,7 @@ GoogleLoginSerializer, OAuthLoginSerializer, ) +from users.models import SignUpType UserModel = get_user_model() @@ -131,3 +134,31 @@ def test_OAuthLoginSerializer_calls_is_authentication_method_valid_correctly_if_ email=user_email, raise_exception=True, ) + + +def test_OAuthLoginSerializer_allows_registration_if_sign_up_type_is_invite_link( + settings: SettingsWrapper, rf: RequestFactory, mocker: MockerFixture, db: None +): + # Given + settings.ALLOW_REGISTRATION_WITHOUT_INVITE = False + + request = rf.post("/api/v1/auth/users/") + user_email = "test_user@test.com" + + serializer = OAuthLoginSerializer( + data={ + "access_token": "some_token", + "sign_up_type": SignUpType.INVITE_LINK.value, + }, + context={"request": request}, + ) + # monkey patch the get_user_info method to return the mock user data + serializer.get_user_info = lambda: {"email": user_email} + + serializer.is_valid(raise_exception=True) + + # When + user = serializer.save() + + # Then + assert user diff --git a/api/custom_auth/serializers.py b/api/custom_auth/serializers.py index 295d427dd532..8709eeae12f9 100644 --- a/api/custom_auth/serializers.py +++ b/api/custom_auth/serializers.py @@ -7,7 +7,7 @@ from organisations.invites.models import Invite from users.constants import DEFAULT_DELETE_ORPHAN_ORGANISATIONS_VALUE -from users.models import FFAdminUser +from users.models import FFAdminUser, SignUpType from .constants import USER_REGISTRATION_WITHOUT_INVITE_ERROR_MESSAGE @@ -64,6 +64,7 @@ def get_key(instance): def save(self, **kwargs): if not ( settings.ALLOW_REGISTRATION_WITHOUT_INVITE + or self.validated_data.get("sign_up_type") == SignUpType.INVITE_LINK.value or Invite.objects.filter(email=self.validated_data.get("email")) ): raise PermissionDenied(USER_REGISTRATION_WITHOUT_INVITE_ERROR_MESSAGE) diff --git a/api/custom_auth/tests/test_serializer.py b/api/custom_auth/tests/test_serializer.py index 25efd23924f9..a00089baaed2 100644 --- a/api/custom_auth/tests/test_serializer.py +++ b/api/custom_auth/tests/test_serializer.py @@ -1,5 +1,8 @@ +from django.test import RequestFactory +from pytest_django.fixtures import SettingsWrapper + from custom_auth.serializers import CustomUserCreateSerializer -from users.models import FFAdminUser +from users.models import FFAdminUser, SignUpType user_dict = { "email": "TestUser@mail.com", @@ -53,3 +56,28 @@ def test_CustomUserCreateSerializer_calls_is_authentication_method_valid_correct email=user_dict["email"], raise_exception=True, ) + + +def test_CustomUserCreateSerializer_allows_registration_if_sign_up_type_is_invite_link( + db: None, + settings: SettingsWrapper, + rf: RequestFactory, +) -> None: + # Given + settings.ALLOW_REGISTRATION_WITHOUT_INVITE = False + + data = { + **user_dict, + "sign_up_type": SignUpType.INVITE_LINK.value, + } + + serializer = CustomUserCreateSerializer( + data=data, context={"request": rf.post("/v1/auth/users/")} + ) + assert serializer.is_valid() + + # When + user = serializer.save() + + # Then + assert user