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

1"""Module that implements the use case for accepting a user invitation.""" 

2 

3from dataclasses import dataclass 

4 

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 

17 

18 

19@dataclass(kw_only=True, frozen=True, slots=False) 

20class AcceptUserInvitationCommand: 

21 """Input for the AcceptUserInvitation use case. 

22 

23 See: [AcceptUserInvitation][kwai.modules.identity.accept_user_invitation.AcceptUserInvitation] 

24 

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 """ 

33 

34 uuid: str 

35 email: str 

36 first_name: str 

37 last_name: str 

38 password: str 

39 remark: str 

40 

41 

42class AcceptUserInvitation: 

43 """Use case for accepting a user invitation.""" 

44 

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. 

52 

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 

61 

62 async def execute(self, command: AcceptUserInvitationCommand) -> None: 

63 """Execute the use case. 

64 

65 Args: 

66 command: The input for this use case. 

67 

68 Returns: 

69 An entity for a user account. 

70 

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 ) 

93 

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 ) 

99 

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 ) 

108 

109 user_invitation = user_invitation.confirm() 

110 await self._user_invitation_repo.update(user_invitation) 

111 

112 user_account = await self._user_account_repo.create(user_account) 

113 self._presenter.present(user_account)