Coverage for bc/kwai-bc-identity/src/kwai_bc_identity/accept_user_invitation.py: 100%

33 statements  

« prev     ^ index     » next       coverage.py v7.11.0, 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 

10 

11from kwai_bc_identity.user_invitations.user_invitation_repository import ( 

12 UserInvitationRepository, 

13) 

14from kwai_bc_identity.users.user import UserEntity 

15from kwai_bc_identity.users.user_account import UserAccountEntity 

16from kwai_bc_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_bc_identity.accept_user_invitation.AcceptUserInvitation] 

24 

25 Attributes: 

26 uuid: The unique id of the user invitation. 

27 first_name: The first name of the new user. 

28 last_name: The last name of the new user. 

29 password: The password for the new user. 

30 remark: A remark about the new user. 

31 """ 

32 

33 uuid: str 

34 first_name: str 

35 last_name: str 

36 password: str 

37 remark: str 

38 

39 

40class AcceptUserInvitation: 

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

42 

43 def __init__( 

44 self, 

45 user_invitation_repo: UserInvitationRepository, 

46 user_account_repo: UserAccountRepository, 

47 presenter: Presenter[UserAccountEntity], 

48 ): 

49 """Create the use case. 

50 

51 Args: 

52 user_invitation_repo: Repository for checking the user invitation. 

53 user_account_repo: Repository that creates a new user account. 

54 presenter: A presenter for a user account entity. 

55 """ 

56 self._user_invitation_repo = user_invitation_repo 

57 self._user_account_repo = user_account_repo 

58 self._presenter = presenter 

59 

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

61 """Execute the use case. 

62 

63 Args: 

64 command: The input for this use case. 

65 

66 Returns: 

67 An entity for a user account. 

68 

69 Raises: 

70 UserInvitationNotFoundExeption: when the user invitation does not 

71 exist. 

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

73 user. 

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

75 When the user invitation is revoked. 

76 """ 

77 uuid = UniqueId.create_from_string(command.uuid) 

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

79 if user_invitation.revoked: 

80 raise UnprocessableException( 

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

82 ) 

83 if user_invitation.is_expired: 

84 raise UnprocessableException( 

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

86 ) 

87 if user_invitation.confirmed: 

88 raise UnprocessableException( 

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

90 ) 

91 

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

93 raise UnprocessableException( 

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

95 ) 

96 

97 user_account = UserAccountEntity( 

98 user=UserEntity( 

99 email=user_invitation.email, 

100 remark=command.remark, 

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

102 ), 

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

104 ) 

105 

106 user_invitation = user_invitation.confirm() 

107 await self._user_invitation_repo.update(user_invitation) 

108 

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

110 self._presenter.present(user_account)