Fix #4841: Use the plugins login for invitations
parent
3d5b98d2a9
commit
78abcab6d5
|
@ -30,14 +30,13 @@ from taiga.base import exceptions as exc
|
||||||
from taiga.base import response
|
from taiga.base import response
|
||||||
|
|
||||||
from .validators import PublicRegisterValidator
|
from .validators import PublicRegisterValidator
|
||||||
from .validators import PrivateRegisterForExistingUserValidator
|
from .validators import PrivateRegisterValidator
|
||||||
from .validators import PrivateRegisterForNewUserValidator
|
|
||||||
|
|
||||||
from .services import private_register_for_existing_user
|
|
||||||
from .services import private_register_for_new_user
|
from .services import private_register_for_new_user
|
||||||
from .services import public_register
|
from .services import public_register
|
||||||
from .services import make_auth_response_data
|
from .services import make_auth_response_data
|
||||||
from .services import get_auth_plugins
|
from .services import get_auth_plugins
|
||||||
|
from .services import accept_invitation_by_existing_user
|
||||||
|
|
||||||
from .permissions import AuthPermission
|
from .permissions import AuthPermission
|
||||||
|
|
||||||
|
@ -61,37 +60,8 @@ def _parse_data(data:dict, *, cls):
|
||||||
# Parse public register data
|
# Parse public register data
|
||||||
parse_public_register_data = partial(_parse_data, cls=PublicRegisterValidator)
|
parse_public_register_data = partial(_parse_data, cls=PublicRegisterValidator)
|
||||||
|
|
||||||
# Parse private register data for existing user
|
|
||||||
parse_private_register_for_existing_user_data = \
|
|
||||||
partial(_parse_data, cls=PrivateRegisterForExistingUserValidator)
|
|
||||||
|
|
||||||
# Parse private register data for new user
|
# Parse private register data for new user
|
||||||
parse_private_register_for_new_user_data = \
|
parse_private_register_data = partial(_parse_data, cls=PrivateRegisterValidator)
|
||||||
partial(_parse_data, cls=PrivateRegisterForNewUserValidator)
|
|
||||||
|
|
||||||
|
|
||||||
class RegisterTypeEnum(Enum):
|
|
||||||
new_user = 1
|
|
||||||
existing_user = 2
|
|
||||||
|
|
||||||
|
|
||||||
def parse_register_type(userdata:dict) -> str:
|
|
||||||
"""
|
|
||||||
Parses user data and detects that register type is.
|
|
||||||
It returns RegisterTypeEnum value.
|
|
||||||
"""
|
|
||||||
# Create adhoc inner serializer for avoid parse
|
|
||||||
# manually the user data.
|
|
||||||
class _validator(validators.Validator):
|
|
||||||
existing = serializers.BooleanField()
|
|
||||||
|
|
||||||
instance = _validator(data=userdata)
|
|
||||||
if not instance.is_valid():
|
|
||||||
raise exc.RequestValidationError(instance.errors)
|
|
||||||
|
|
||||||
if instance.data["existing"]:
|
|
||||||
return RegisterTypeEnum.existing_user
|
|
||||||
return RegisterTypeEnum.new_user
|
|
||||||
|
|
||||||
|
|
||||||
class AuthViewSet(viewsets.ViewSet):
|
class AuthViewSet(viewsets.ViewSet):
|
||||||
|
@ -111,14 +81,8 @@ class AuthViewSet(viewsets.ViewSet):
|
||||||
return response.Created(data)
|
return response.Created(data)
|
||||||
|
|
||||||
def _private_register(self, request):
|
def _private_register(self, request):
|
||||||
register_type = parse_register_type(request.DATA)
|
data = parse_private_register_data(request.DATA)
|
||||||
|
user = private_register_for_new_user(**data)
|
||||||
if register_type is RegisterTypeEnum.existing_user:
|
|
||||||
data = parse_private_register_for_existing_user_data(request.DATA)
|
|
||||||
user = private_register_for_existing_user(**data)
|
|
||||||
else:
|
|
||||||
data = parse_private_register_for_new_user_data(request.DATA)
|
|
||||||
user = private_register_for_new_user(**data)
|
|
||||||
|
|
||||||
data = make_auth_response_data(user)
|
data = make_auth_response_data(user)
|
||||||
return response.Created(data)
|
return response.Created(data)
|
||||||
|
@ -140,9 +104,13 @@ class AuthViewSet(viewsets.ViewSet):
|
||||||
auth_plugins = get_auth_plugins()
|
auth_plugins = get_auth_plugins()
|
||||||
|
|
||||||
login_type = request.DATA.get("type", None)
|
login_type = request.DATA.get("type", None)
|
||||||
|
invitation_token = request.DATA.get("invitation_token", None)
|
||||||
|
|
||||||
if login_type in auth_plugins:
|
if login_type in auth_plugins:
|
||||||
data = auth_plugins[login_type]['login_func'](request)
|
data = auth_plugins[login_type]['login_func'](request)
|
||||||
|
if invitation_token:
|
||||||
|
accept_invitation_by_existing_user(invitation_token, data['id'])
|
||||||
return response.Ok(data)
|
return response.Ok(data)
|
||||||
|
|
||||||
|
|
||||||
raise exc.BadRequest(_("invalid login type"))
|
raise exc.BadRequest(_("invalid login type"))
|
||||||
|
|
|
@ -128,16 +128,9 @@ def public_register(username:str, password:str, email:str, full_name:str):
|
||||||
|
|
||||||
|
|
||||||
@tx.atomic
|
@tx.atomic
|
||||||
def private_register_for_existing_user(token:str, username:str, password:str):
|
def accept_invitation_by_existing_user(token:str, user_id:int):
|
||||||
"""
|
user_model = get_user_model()
|
||||||
Register works not only for register users, also serves for accept
|
user = user_model.objects.get(id=user_id)
|
||||||
inviatations for projects as existing user.
|
|
||||||
|
|
||||||
Given a invitation token with parsed parameters, accept inviation
|
|
||||||
as existing user.
|
|
||||||
"""
|
|
||||||
|
|
||||||
user = get_and_validate_user(username=username, password=password)
|
|
||||||
membership = get_membership_by_token(token)
|
membership = get_membership_by_token(token)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -145,8 +138,6 @@ def private_register_for_existing_user(token:str, username:str, password:str):
|
||||||
membership.save(update_fields=["user"])
|
membership.save(update_fields=["user"])
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise exc.IntegrityError(_("This user is already a member of the project."))
|
raise exc.IntegrityError(_("This user is already a member of the project."))
|
||||||
|
|
||||||
send_register_email(user)
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,11 +48,5 @@ class PublicRegisterValidator(BaseRegisterValidator):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PrivateRegisterForNewUserValidator(BaseRegisterValidator):
|
class PrivateRegisterValidator(BaseRegisterValidator):
|
||||||
token = serializers.CharField(max_length=255, required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class PrivateRegisterForExistingUserValidator(validators.Validator):
|
|
||||||
username = serializers.CharField(max_length=255)
|
|
||||||
password = serializers.CharField(min_length=4)
|
|
||||||
token = serializers.CharField(max_length=255, required=True)
|
token = serializers.CharField(max_length=255, required=True)
|
||||||
|
|
|
@ -62,23 +62,21 @@ def test_respond_201_when_the_email_domain_is_in_allowed_domains(client, setting
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
def test_respond_201_with_invitation_without_public_registration(client, register_form, settings):
|
def test_respond_201_with_invitation_login(client, settings):
|
||||||
settings.PUBLIC_REGISTER_ENABLED = False
|
settings.PUBLIC_REGISTER_ENABLED = False
|
||||||
user = factories.UserFactory()
|
user = factories.UserFactory()
|
||||||
membership = factories.MembershipFactory(user=user)
|
membership = factories.MembershipFactory(user=user)
|
||||||
|
|
||||||
register_form.update({
|
auth_data = {
|
||||||
"type": "private",
|
"type": "normal",
|
||||||
"existing": "1",
|
"invitation_token": membership.token,
|
||||||
"token": membership.token,
|
|
||||||
"username": user.username,
|
"username": user.username,
|
||||||
"email": user.email,
|
|
||||||
"password": user.username,
|
"password": user.username,
|
||||||
})
|
}
|
||||||
|
|
||||||
response = client.post(reverse("auth-register"), register_form)
|
response = client.post(reverse("auth-list"), auth_data)
|
||||||
|
|
||||||
assert response.status_code == 201, response.data
|
assert response.status_code == 200, response.data
|
||||||
|
|
||||||
|
|
||||||
def test_response_200_in_public_registration(client, settings):
|
def test_response_200_in_public_registration(client, settings):
|
||||||
|
|
Loading…
Reference in New Issue