Coverage for apps/kwai-api/src/kwai_api/v1/club/coaches/endpoints.py: 83%

58 statements  

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

1"""Module for defining endpoints for coaches of the club API.""" 

2 

3from typing import Annotated 

4 

5from fastapi import APIRouter, Depends, HTTPException, Query, status 

6from kwai_bc_club.create_coach import CreateCoach, CreateCoachCommand 

7from kwai_bc_club.get_coaches import GetCoaches, GetCoachesCommand 

8from kwai_bc_club.repositories.coach_db_repository import CoachDbRepository 

9from kwai_bc_club.repositories.coach_repository import ( 

10 CoachAlreadyExistException, 

11 CoachNotFoundException, 

12) 

13from kwai_bc_club.repositories.member_db_repository import MemberDbRepository 

14from kwai_bc_club.repositories.member_repository import MemberNotFoundException 

15from kwai_bc_club.update_coach import UpdateCoach, UpdateCoachCommand 

16from kwai_bc_identity.users.user import UserEntity 

17from kwai_core.db.database import Database 

18from kwai_core.db.uow import UnitOfWork 

19from kwai_core.json_api import PaginationModel 

20from pydantic import BaseModel, Field 

21 

22from kwai_api.dependencies import create_database, get_current_user, get_optional_user 

23from kwai_api.v1.club.coaches.presenters import ( 

24 JsonApiCoachesPresenter, 

25 JsonApiCoachPresenter, 

26 JsonApiPublicCoachesPresenter, 

27) 

28from kwai_api.v1.club.coaches.schemas import ( 

29 CoachDocument, 

30 CoachesDocument, 

31 PublicCoachesDocument, 

32) 

33 

34 

35router = APIRouter() 

36 

37 

38class CoachesFilterModel(BaseModel): 

39 """JSON:API filter for coaches.""" 

40 

41 enabled: bool = Field(Query(default=True, alias="filter[enabled]")) 

42 

43 

44@router.get("/coaches") 

45async def get_coaches( 

46 pagination: Annotated[PaginationModel, Depends(PaginationModel)], 

47 coaches_filter: Annotated[CoachesFilterModel, Depends(CoachesFilterModel)], 

48 db: Annotated[Database, Depends(create_database)], 

49 user: Annotated[UserEntity | None, Depends(get_optional_user)], 

50) -> PublicCoachesDocument | CoachesDocument: 

51 """Get all coaches.""" 

52 if user is None: 

53 presenter = JsonApiPublicCoachesPresenter() 

54 active = True 

55 else: 

56 presenter = JsonApiCoachesPresenter() 

57 active = coaches_filter.enabled 

58 

59 command = GetCoachesCommand( 

60 offset=pagination.offset, limit=pagination.limit, active=active 

61 ) 

62 await GetCoaches(CoachDbRepository(db), presenter).execute(command) 

63 

64 return presenter.get_document() 

65 

66 

67@router.post( 

68 "/coaches", 

69 responses={ 

70 status.HTTP_201_CREATED: {"description": "Coach was created."}, 

71 status.HTTP_404_NOT_FOUND: {"description": "Member is not found."}, 

72 status.HTTP_409_CONFLICT: {"description": "Coach already exists."}, 

73 status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Data is invalid."}, 

74 }, 

75 status_code=status.HTTP_201_CREATED, 

76) 

77async def create_coach( 

78 db: Annotated[Database, Depends(create_database)], 

79 user: Annotated[UserEntity, Depends(get_current_user)], 

80 resource: CoachDocument, 

81) -> CoachDocument: 

82 """Create a new coach.""" 

83 if ( 

84 resource.data.relationships is None 

85 or resource.data.relationships.member is None 

86 or resource.data.relationships.member.data is None 

87 or resource.data.relationships.member.data.id is None 

88 ): 

89 raise HTTPException( 

90 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, 

91 detail="Member relationship data is missing.", 

92 ) 

93 

94 command = CreateCoachCommand( 

95 description=resource.data.attributes.description, 

96 diploma=resource.data.attributes.diploma, 

97 remark=resource.data.attributes.remark, 

98 active=resource.data.attributes.active, 

99 member_uuid=resource.data.relationships.member.data.id, 

100 ) 

101 presenter = JsonApiCoachPresenter() 

102 

103 async with UnitOfWork(db): 

104 try: 

105 await CreateCoach( 

106 CoachDbRepository(db), MemberDbRepository(db), presenter 

107 ).execute(command) 

108 except MemberNotFoundException as ex: 

109 raise HTTPException( 

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

111 ) from ex 

112 except CoachAlreadyExistException as ex: 

113 raise HTTPException( 

114 status_code=status.HTTP_409_CONFLICT, detail=str(ex) 

115 ) from ex 

116 except ValueError as ve: 

117 raise HTTPException( 

118 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ve) 

119 ) from ve 

120 

121 return presenter.get_document() 

122 

123 

124@router.patch( 

125 "/coaches/{coach_id}", 

126 responses={status.HTTP_404_NOT_FOUND: {"description": "Coach was not found."}}, 

127) 

128async def update_coach( 

129 db: Annotated[Database, Depends(create_database)], 

130 user: Annotated[UserEntity, Depends(get_current_user)], 

131 coach_id: int, 

132 resource: CoachDocument, 

133) -> CoachDocument: 

134 """Update a coach.""" 

135 command = UpdateCoachCommand( 

136 id=coach_id, 

137 diploma=resource.data.attributes.diploma, 

138 description=resource.data.attributes.description, 

139 active=resource.data.attributes.active, 

140 remark=resource.data.attributes.remark, 

141 ) 

142 presenter = JsonApiCoachPresenter() 

143 async with UnitOfWork(db): 

144 try: 

145 await UpdateCoach(CoachDbRepository(db), presenter).execute(command) 

146 except CoachNotFoundException as ex: 

147 raise HTTPException( 

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

149 ) from ex 

150 except ValueError as ve: 

151 raise HTTPException( 

152 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ve) 

153 ) from ve 

154 

155 return presenter.get_document()