Coverage for src/kwai/modules/identity/accept_user_invitation.py: 100%
41 statements
« prev ^ index » next coverage.py v7.7.1, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2024-01-01 00:00 +0000
1"""Module that implements the use case for accepting a user invitation."""
3from dataclasses import dataclass
5from kwai.core.domain.exceptions import UnprocessableException
6from kwai.core.domain.presenter import Presenter
7from kwai.core.domain.value_objects.email_address import EmailAddress
8from kwai.core.domain.value_objects.name import Name
9from kwai.core.domain.value_objects.password import Password
10from kwai.core.domain.value_objects.unique_id import UniqueId
11from kwai.modules.identity.user_invitations.user_invitation_repository import (
12 UserInvitationRepository,
13)
14from kwai.modules.identity.users.user import UserEntity
15from kwai.modules.identity.users.user_account import UserAccountEntity
16from kwai.modules.identity.users.user_account_repository import UserAccountRepository
19@dataclass(kw_only=True, frozen=True, slots=False)
20class AcceptUserInvitationCommand:
21 """Input for the AcceptUserInvitation use case.
23 See: [AcceptUserInvitation][kwai.modules.identity.accept_user_invitation.AcceptUserInvitation]
25 Attributes:
26 uuid: The unique id of the user invitation.
27 email: The email address for the new user.
28 first_name: The first name of the new user.
29 last_name: The last name of the new user.
30 password: The password for the new user.
31 remark: A remark about the new user.
32 """
34 uuid: str
35 email: str
36 first_name: str
37 last_name: str
38 password: str
39 remark: str
42class AcceptUserInvitation:
43 """Use case for accepting a user invitation."""
45 def __init__(
46 self,
47 user_invitation_repo: UserInvitationRepository,
48 user_account_repo: UserAccountRepository,
49 presenter: Presenter[UserAccountEntity],
50 ):
51 """Create the use case.
53 Args:
54 user_invitation_repo: Repository for checking the user invitation.
55 user_account_repo: Repository that creates a new user account.
56 presenter: A presenter for a user account entity.
57 """
58 self._user_invitation_repo = user_invitation_repo
59 self._user_account_repo = user_account_repo
60 self._presenter = presenter
62 async def execute(self, command: AcceptUserInvitationCommand) -> None:
63 """Execute the use case.
65 Args:
66 command: The input for this use case.
68 Returns:
69 An entity for a user account.
71 Raises:
72 UserInvitationNotFoundExeption: when the user invitation does not
73 exist.
74 UnprocessableException: when the email address is already used by another
75 user.
76 When the user invitation is expired or was already accepted.
77 When the user invitation is revoked.
78 """
79 uuid = UniqueId.create_from_string(command.uuid)
80 user_invitation = await self._user_invitation_repo.get_invitation_by_uuid(uuid)
81 if user_invitation.revoked:
82 raise UnprocessableException(
83 f"The user invitation with id {uuid} is revoked."
84 )
85 if user_invitation.is_expired:
86 raise UnprocessableException(
87 f"The user invitation with id {uuid} is expired."
88 )
89 if user_invitation.confirmed:
90 raise UnprocessableException(
91 f"The user invitation with id {uuid} was already accepted."
92 )
94 email = EmailAddress(command.email)
95 if await self._user_account_repo.exists_with_email(email):
96 raise UnprocessableException(
97 f"A user with email {command.email} already exists."
98 )
100 user_account = UserAccountEntity(
101 user=UserEntity(
102 email=email,
103 remark=command.remark,
104 name=Name(first_name=command.first_name, last_name=command.last_name),
105 ),
106 password=Password.create_from_string(command.password),
107 )
109 user_invitation = user_invitation.confirm()
110 await self._user_invitation_repo.update(user_invitation)
112 user_account = await self._user_account_repo.create(user_account)
113 self._presenter.present(user_account)