Coverage for src/kwai/api/v1/auth/endpoints/user_invitations.py: 80%

55 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2024-01-01 00:00 +0000

1"""Module that implements invitations endpoints.""" 

2 

3from fastapi import APIRouter, Depends, HTTPException, status 

4from loguru import logger 

5 

6from kwai.api.dependencies import create_database, get_current_user, get_publisher 

7from kwai.api.v1.auth.schemas.user_invitation import UserInvitationDocument 

8from kwai.core.db.uow import UnitOfWork 

9from kwai.core.domain.exceptions import UnprocessableException 

10from kwai.core.domain.value_objects.email_address import InvalidEmailException 

11from kwai.core.json_api import Meta, PaginationModel 

12from kwai.modules.identity.delete_user_invitation import ( 

13 DeleteUserInvitation, 

14 DeleteUserInvitationCommand, 

15) 

16from kwai.modules.identity.get_invitations import GetInvitations, GetInvitationsCommand 

17from kwai.modules.identity.get_user_invitation import ( 

18 GetUserInvitation, 

19 GetUserInvitationCommand, 

20) 

21from kwai.modules.identity.invite_user import InviteUser, InviteUserCommand 

22from kwai.modules.identity.user_invitations.user_invitation_db_repository import ( 

23 UserInvitationDbRepository, 

24) 

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

26 UserInvitationNotFoundException, 

27) 

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

29from kwai.modules.identity.users.user_db_repository import UserDbRepository 

30 

31 

32router = APIRouter() 

33 

34 

35@router.post( 

36 "/invitations", 

37 summary="Create a user invitation", 

38 status_code=status.HTTP_201_CREATED, 

39 responses={ 

40 201: {"description": "User invitation is created"}, 

41 401: {"description": "Not authorized."}, 

42 422: {"description": "User invitation could not be created"}, 

43 }, 

44) 

45async def create_user_invitation( 

46 user_invitation_document: UserInvitationDocument, 

47 db=Depends(create_database), 

48 user: UserEntity = Depends(get_current_user), 

49 publisher=Depends(get_publisher), 

50) -> UserInvitationDocument: 

51 """Create a user invitation. 

52 

53 A wrong email address or a still pending user invitation will result in a 422 

54 status code. 

55 """ 

56 command = InviteUserCommand( 

57 first_name=user_invitation_document.resource.attributes.first_name, 

58 last_name=user_invitation_document.resource.attributes.last_name, 

59 email=user_invitation_document.resource.attributes.email, 

60 remark=user_invitation_document.resource.attributes.remark, 

61 ) 

62 

63 try: 

64 async with UnitOfWork(db): 

65 invitation = await InviteUser( 

66 user, UserDbRepository(db), UserInvitationDbRepository(db), publisher 

67 ).execute(command) 

68 except InvalidEmailException as exc: 

69 raise HTTPException( 

70 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

71 detail="Invalid email address", 

72 ) from exc 

73 except UnprocessableException as ex: 

74 logger.warning(f"User invitation could not be processed: {ex}") 

75 raise HTTPException( 

76 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex) 

77 ) from ex 

78 

79 return UserInvitationDocument.create(invitation) 

80 

81 

82@router.delete( 

83 "/invitations/{uuid}", 

84 summary="Delete a user invitation", 

85 status_code=status.HTTP_200_OK, 

86 responses={ 

87 200: {"description": "User invitation is deleted."}, 

88 401: {"description": "Not authorized."}, 

89 404: {"description": "User invitation does not exist."}, 

90 422: {"description": "Invalid unique id passed for the user invitation."}, 

91 }, 

92) 

93async def delete_user_invitation( 

94 uuid: str, 

95 db=Depends(create_database), 

96 user: UserEntity = Depends(get_current_user), 

97) -> None: 

98 """Delete the user invitation with the given unique id.""" 

99 command = DeleteUserInvitationCommand(uuid=uuid) 

100 try: 

101 async with UnitOfWork(db): 

102 await DeleteUserInvitation(UserInvitationDbRepository(db)).execute(command) 

103 except UserInvitationNotFoundException as ex: 

104 raise HTTPException( 

105 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) 

106 ) from ex 

107 except ValueError as ex: 

108 raise HTTPException( 

109 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex) 

110 ) from ex 

111 

112 

113@router.get( 

114 "/invitations", 

115 summary="Get a list of user invitations", 

116 responses={ 

117 200: {"description": "Ok."}, 

118 401: {"description": "Not authorized."}, 

119 }, 

120) 

121async def get_user_invitations( 

122 pagination: PaginationModel = Depends(PaginationModel), 

123 db=Depends(create_database), 

124 user: UserEntity = Depends(get_current_user), 

125) -> UserInvitationDocument: 

126 """Get all user invitations. 

127 

128 Use the page[offset] and page[limit] query parameters to get a paginated result. 

129 """ 

130 command = GetInvitationsCommand(offset=pagination.offset, limit=pagination.limit) 

131 count, invitation_iterator = await GetInvitations( 

132 UserInvitationDbRepository(db) 

133 ).execute(command) 

134 

135 result = UserInvitationDocument( 

136 meta=Meta(count=count, limit=pagination.limit, offset=pagination.offset), 

137 data=[], 

138 ) 

139 

140 async for invitation in invitation_iterator: 

141 result.merge(UserInvitationDocument.create(invitation)) 

142 

143 return result 

144 

145 

146@router.get( 

147 "/invitations/{uuid}", 

148 summary="Get a user invitation", 

149 responses={200: {"description": "Ok."}, 401: {"description": "Not authorized."}}, 

150) 

151async def get_user_invitation( 

152 uuid: str, 

153 db=Depends(create_database), 

154 user: UserEntity = Depends(get_current_user), 

155) -> UserInvitationDocument: 

156 """Get the user invitation with the given unique id.""" 

157 command = GetUserInvitationCommand(uuid=uuid) 

158 try: 

159 invitation = await GetUserInvitation(UserInvitationDbRepository(db)).execute( 

160 command 

161 ) 

162 except UserInvitationNotFoundException as ex: 

163 raise HTTPException( 

164 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) 

165 ) from ex 

166 

167 return UserInvitationDocument.create(invitation)