Coverage for apps/kwai-api/src/kwai_api/v1/auth/endpoints/user_invitations.py: 71%
85 statements
« prev ^ index » next coverage.py v7.11.0, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2024-01-01 00:00 +0000
1"""Module that implements invitations endpoints."""
3from typing import Annotated
5from fastapi import APIRouter, Depends, HTTPException, status
6from kwai_bc_identity.delete_user_invitation import (
7 DeleteUserInvitation,
8 DeleteUserInvitationCommand,
9)
10from kwai_bc_identity.get_invitations import GetInvitations, GetInvitationsCommand
11from kwai_bc_identity.get_user_invitation import (
12 GetUserInvitation,
13 GetUserInvitationCommand,
14)
15from kwai_bc_identity.invite_user import InviteUser, InviteUserCommand
16from kwai_bc_identity.recreate_user_invitation import (
17 RecreateUserInvitation,
18 RecreateUserInvitationCommand,
19)
20from kwai_bc_identity.update_user_invitation import (
21 UpdateUserInvitation,
22 UpdateUserInvitationCommand,
23)
24from kwai_bc_identity.user_invitations.user_invitation_db_repository import (
25 UserInvitationDbRepository,
26)
27from kwai_bc_identity.user_invitations.user_invitation_repository import (
28 UserInvitationNotFoundException,
29)
30from kwai_bc_identity.users.user import UserEntity
31from kwai_bc_identity.users.user_db_repository import UserDbRepository
32from kwai_core.db.database import Database
33from kwai_core.db.uow import UnitOfWork
34from kwai_core.domain.exceptions import UnprocessableException
35from kwai_core.domain.value_objects.email_address import InvalidEmailException
36from kwai_core.events.publisher import Publisher
37from kwai_core.json_api import PaginationModel
38from loguru import logger
40from kwai_api.dependencies import create_database, get_current_user, get_publisher
41from kwai_api.v1.auth.presenters import (
42 JsonApiUserInvitationPresenter,
43 JsonApiUserInvitationsPresenter,
44)
45from kwai_api.v1.auth.schemas.user_invitation import (
46 UserInvitationDocument,
47 UserInvitationsDocument,
48)
51router = APIRouter()
54@router.post(
55 "/invitations/{uuid}",
56 summary="Recreate a user invitation",
57 status_code=status.HTTP_201_CREATED,
58 responses={
59 201: {"description": "User invitation is created"},
60 401: {"description": "Not authorized."},
61 422: {"description": "User invitation could not be created"},
62 },
63)
64async def recreate_user_invitation(
65 uuid: str,
66 db: Annotated[Database, Depends(create_database)],
67 user: Annotated[UserEntity, Depends(get_current_user)],
68 publisher: Annotated[Publisher, Depends(get_publisher)],
69) -> UserInvitationDocument:
70 """Recreate a user invitation.
72 Use this API for resending a user invitation. The existing invitation
73 will expire.
74 """
75 command = RecreateUserInvitationCommand(uuid=uuid)
76 presenter = JsonApiUserInvitationPresenter()
77 try:
78 async with UnitOfWork(db):
79 await RecreateUserInvitation(
80 user,
81 UserDbRepository(db),
82 UserInvitationDbRepository(db),
83 presenter,
84 publisher,
85 ).execute(command)
86 except UnprocessableException as ex:
87 logger.warning(f"User invitation could not be processed: {ex}")
88 raise HTTPException(
89 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex)
90 ) from ex
92 return presenter.get_document()
95@router.patch(
96 "/invitations/{id}",
97 summary="Update a user invitation",
98)
99async def update_user_invitation(
100 id: str,
101 user_invitation_document: UserInvitationDocument,
102 db=Depends(create_database),
103 user: UserEntity = Depends(get_current_user),
104) -> UserInvitationDocument:
105 """Update a user invitation."""
106 command = UpdateUserInvitationCommand(
107 uuid=id,
108 revoked=user_invitation_document.data.attributes.revoked,
109 remark=user_invitation_document.data.attributes.remark,
110 )
111 presenter = JsonApiUserInvitationPresenter()
112 try:
113 async with UnitOfWork(db):
114 await UpdateUserInvitation(
115 UserInvitationDbRepository(db), presenter
116 ).execute(command)
117 except InvalidEmailException as exc:
118 raise HTTPException(
119 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
120 detail="Invalid email address",
121 ) from exc
122 except UnprocessableException as ex:
123 logger.warning(f"User invitation could not be processed: {ex}")
124 raise HTTPException(
125 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex)
126 ) from ex
128 return presenter.get_document()
131@router.post(
132 "/invitations",
133 summary="Create a user invitation",
134 status_code=status.HTTP_201_CREATED,
135 responses={
136 201: {"description": "User invitation is created"},
137 401: {"description": "Not authorized."},
138 422: {"description": "User invitation could not be created"},
139 },
140)
141async def create_user_invitation(
142 user_invitation_document: UserInvitationDocument,
143 db=Depends(create_database),
144 user: UserEntity = Depends(get_current_user),
145 publisher=Depends(get_publisher),
146) -> UserInvitationDocument:
147 """Create a user invitation.
149 A wrong email address or a still pending user invitation will result in a 422
150 status code.
151 """
152 command = InviteUserCommand(
153 first_name=user_invitation_document.data.attributes.first_name,
154 last_name=user_invitation_document.data.attributes.last_name,
155 email=user_invitation_document.data.attributes.email,
156 remark=user_invitation_document.data.attributes.remark,
157 )
158 presenter = JsonApiUserInvitationPresenter()
159 try:
160 async with UnitOfWork(db):
161 await InviteUser(
162 user,
163 UserDbRepository(db),
164 UserInvitationDbRepository(db),
165 presenter,
166 publisher,
167 ).execute(command)
168 except InvalidEmailException as exc:
169 raise HTTPException(
170 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
171 detail="Invalid email address",
172 ) from exc
173 except UnprocessableException as ex:
174 logger.warning(f"User invitation could not be processed: {ex}")
175 raise HTTPException(
176 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex)
177 ) from ex
179 return presenter.get_document()
182@router.delete(
183 "/invitations/{uuid}",
184 summary="Delete a user invitation",
185 status_code=status.HTTP_200_OK,
186 responses={
187 200: {"description": "User invitation is deleted."},
188 401: {"description": "Not authorized."},
189 404: {"description": "User invitation does not exist."},
190 422: {"description": "Invalid unique id passed for the user invitation."},
191 },
192)
193async def delete_user_invitation(
194 uuid: str,
195 db=Depends(create_database),
196 user: UserEntity = Depends(get_current_user),
197) -> None:
198 """Delete the user invitation with the given unique id."""
199 command = DeleteUserInvitationCommand(uuid=uuid)
200 try:
201 async with UnitOfWork(db):
202 await DeleteUserInvitation(UserInvitationDbRepository(db)).execute(command)
203 except UserInvitationNotFoundException as ex:
204 raise HTTPException(
205 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)
206 ) from ex
207 except ValueError as ex:
208 raise HTTPException(
209 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex)
210 ) from ex
213@router.get(
214 "/invitations",
215 summary="Get a list of user invitations",
216 responses={
217 200: {"description": "Ok."},
218 401: {"description": "Not authorized."},
219 },
220)
221async def get_user_invitations(
222 pagination: PaginationModel = Depends(PaginationModel),
223 db=Depends(create_database),
224 user: UserEntity = Depends(get_current_user),
225) -> UserInvitationsDocument:
226 """Get all user invitations.
228 Use the page[offset] and page[limit] query parameters to get a paginated result.
229 """
230 command = GetInvitationsCommand(offset=pagination.offset, limit=pagination.limit)
231 presenter = JsonApiUserInvitationsPresenter()
232 await GetInvitations(UserInvitationDbRepository(db), presenter).execute(command)
234 return presenter.get_document()
237@router.get(
238 "/invitations/{uuid}",
239 summary="Get a user invitation",
240 responses={200: {"description": "Ok."}, 401: {"description": "Not authorized."}},
241)
242async def get_user_invitation(
243 uuid: str,
244 db=Depends(create_database),
245 user: UserEntity = Depends(get_current_user),
246) -> UserInvitationDocument:
247 """Get the user invitation with the given unique id."""
248 command = GetUserInvitationCommand(uuid=uuid)
249 presenter = JsonApiUserInvitationPresenter()
250 try:
251 await GetUserInvitation(UserInvitationDbRepository(db), presenter).execute(
252 command
253 )
254 except UserInvitationNotFoundException as ex:
255 raise HTTPException(
256 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)
257 ) from ex
259 return presenter.get_document()