Coverage for src/kwai/modules/identity/accept_user_invitation.py: 100%

38 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.name import Name 

8from kwai.core.domain.value_objects.password import Password 

9from kwai.core.domain.value_objects.unique_id import UniqueId 

10from kwai.modules.identity.user_invitations.user_invitation_repository import ( 

11 UserInvitationRepository, 

12) 

13from kwai.modules.identity.users.user import UserEntity 

14from kwai.modules.identity.users.user_account import UserAccountEntity 

15from kwai.modules.identity.users.user_account_repository import UserAccountRepository 

16 

17 

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

19class AcceptUserInvitationCommand: 

20 """Input for the AcceptUserInvitation use case. 

21 

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

23 

24 Attributes: 

25 uuid: The unique id of the user invitation. 

26 first_name: The first name of the new user. 

27 last_name: The last name of the new user. 

28 password: The password for the new user. 

29 remark: A remark about the new user. 

30 """ 

31 

32 uuid: str 

33 first_name: str 

34 last_name: str 

35 password: str 

36 remark: str 

37 

38 

39class AcceptUserInvitation: 

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

41 

42 def __init__( 

43 self, 

44 user_invitation_repo: UserInvitationRepository, 

45 user_account_repo: UserAccountRepository, 

46 presenter: Presenter[UserAccountEntity], 

47 ): 

48 """Create the use case. 

49 

50 Args: 

51 user_invitation_repo: Repository for checking the user invitation. 

52 user_account_repo: Repository that creates a new user account. 

53 presenter: A presenter for a user account entity. 

54 """ 

55 self._user_invitation_repo = user_invitation_repo 

56 self._user_account_repo = user_account_repo 

57 self._presenter = presenter 

58 

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

60 """Execute the use case. 

61 

62 Args: 

63 command: The input for this use case. 

64 

65 Returns: 

66 An entity for a user account. 

67 

68 Raises: 

69 UserInvitationNotFoundExeption: when the user invitation does not 

70 exist. 

71 UnprocessableException: when the email address is already used by another 

72 user. 

73 When the user invitation is expired or was already accepted. 

74 When the user invitation is revoked. 

75 """ 

76 uuid = UniqueId.create_from_string(command.uuid) 

77 user_invitation = await self._user_invitation_repo.get_invitation_by_uuid(uuid) 

78 if user_invitation.revoked: 

79 raise UnprocessableException( 

80 f"The user invitation with id {uuid} is revoked." 

81 ) 

82 if user_invitation.is_expired: 

83 raise UnprocessableException( 

84 f"The user invitation with id {uuid} is expired." 

85 ) 

86 if user_invitation.confirmed: 

87 raise UnprocessableException( 

88 f"The user invitation with id {uuid} was already accepted." 

89 ) 

90 

91 if await self._user_account_repo.exists_with_email(user_invitation.email): 

92 raise UnprocessableException( 

93 f"A user with email {user_invitation.email} already exists." 

94 ) 

95 

96 user_account = UserAccountEntity( 

97 user=UserEntity( 

98 email=user_invitation.email, 

99 remark=command.remark, 

100 name=Name(first_name=command.first_name, last_name=command.last_name), 

101 ), 

102 password=Password.create_from_string(command.password), 

103 ) 

104 

105 user_invitation = user_invitation.confirm() 

106 await self._user_invitation_repo.update(user_invitation) 

107 

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

109 self._presenter.present(user_account)