Coverage for apps/kwai-api/src/kwai_api/v1/trainings/endpoints.py: 86%

83 statements  

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

1"""Module for endpoints for trainings.""" 

2 

3from datetime import datetime 

4 

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

6from kwai_bc_identity.users.user import UserEntity 

7from kwai_bc_training.coaches.coach_db_repository import CoachDbRepository 

8from kwai_bc_training.coaches.coach_repository import CoachNotFoundException 

9from kwai_bc_training.create_training import CreateTraining, CreateTrainingCommand 

10from kwai_bc_training.delete_training import DeleteTraining, DeleteTrainingCommand 

11from kwai_bc_training.get_training import GetTraining, GetTrainingCommand 

12from kwai_bc_training.get_trainings import GetTrainings, GetTrainingsCommand 

13from kwai_bc_training.teams.team_db_repository import TeamDbRepository 

14from kwai_bc_training.training_command import Coach 

15from kwai_bc_training.trainings.training_db_repository import TrainingDbRepository 

16from kwai_bc_training.trainings.training_repository import TrainingNotFoundException 

17from kwai_bc_training.trainings.training_schedule_db_repository import ( 

18 TrainingScheduleDbRepository, 

19) 

20from kwai_bc_training.trainings.training_schedule_repository import ( 

21 TrainingScheduleNotFoundException, 

22) 

23from kwai_bc_training.update_training import UpdateTraining, UpdateTrainingCommand 

24from kwai_core.db.uow import UnitOfWork 

25from kwai_core.domain.use_case import TextCommand 

26from kwai_core.domain.value_objects.owner import Owner 

27from kwai_core.json_api import PaginationModel 

28from pydantic import BaseModel, Field 

29 

30from kwai_api.dependencies import create_database, get_current_user 

31from kwai_api.v1.trainings.coaches.schemas import TrainingCoachResource 

32from kwai_api.v1.trainings.presenters import ( 

33 JsonApiTrainingPresenter, 

34 JsonApiTrainingsDocumentPresenter, 

35) 

36from kwai_api.v1.trainings.schemas import TrainingDocument, TrainingsDocument 

37 

38 

39router = APIRouter() 

40 

41 

42class TrainingsFilterModel(BaseModel): 

43 """Define the JSON:API filter for trainings.""" 

44 

45 year: int | None = Field(Query(default=None, alias="filter[year]")) 

46 month: int | None = Field(Query(default=None, alias="filter[month]")) 

47 start: datetime | None = Field(Query(default=None, alias="filter[start]")) 

48 end: datetime | None = Field(Query(default=None, alias="filter[end]")) 

49 active: bool = Field(Query(default=True, alias="filter[active]")) 

50 coach: int | None = Field(Query(default=None, alias="filter[coach]")) 

51 schedule: int | None = Field(Query(default=None, alias="filter[schedule]")) 

52 

53 

54@router.get( 

55 "/trainings", 

56 responses={ 

57 status.HTTP_404_NOT_FOUND: { 

58 "description": "Coach or Training schedule was not found." 

59 } 

60 }, 

61) 

62async def get_trainings( 

63 pagination: PaginationModel = Depends(PaginationModel), 

64 trainings_filter: TrainingsFilterModel = Depends(TrainingsFilterModel), 

65 db=Depends(create_database), 

66) -> TrainingsDocument: 

67 """Get all trainings.""" 

68 command = GetTrainingsCommand( 

69 offset=pagination.offset or 0, 

70 limit=pagination.limit, 

71 year=trainings_filter.year, 

72 month=trainings_filter.month, 

73 start=trainings_filter.start, 

74 end=trainings_filter.end, 

75 active=trainings_filter.active, 

76 coach=trainings_filter.coach, 

77 schedule=trainings_filter.schedule, 

78 ) 

79 presenter = JsonApiTrainingsDocumentPresenter() 

80 try: 

81 await GetTrainings( 

82 TrainingDbRepository(db), 

83 CoachDbRepository(db), 

84 TrainingScheduleDbRepository(db), 

85 presenter, 

86 ).execute(command) 

87 except TrainingScheduleNotFoundException as ex: 

88 raise HTTPException( 

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

90 ) from ex 

91 except CoachNotFoundException as ex: 

92 raise HTTPException( 

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

94 ) from ex 

95 

96 return presenter.get_document() 

97 

98 

99@router.get( 

100 "/trainings/{training_id}", 

101 responses={status.HTTP_404_NOT_FOUND: {"description": "Training was not found."}}, 

102) 

103async def get_training( 

104 training_id: int, 

105 db=Depends(create_database), 

106) -> TrainingDocument: 

107 """Get the training with the given id.""" 

108 command = GetTrainingCommand(id=training_id) 

109 presenter = JsonApiTrainingPresenter() 

110 try: 

111 await GetTraining(TrainingDbRepository(db), presenter).execute(command) 

112 except TrainingNotFoundException as ex: 

113 raise HTTPException( 

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

115 ) from ex 

116 

117 return presenter.get_document() 

118 

119 

120@router.post( 

121 "/trainings", 

122 status_code=status.HTTP_201_CREATED, 

123) 

124async def create_training( 

125 resource: TrainingDocument, 

126 db=Depends(create_database), 

127 user: UserEntity = Depends(get_current_user), 

128) -> TrainingDocument: 

129 """Create a new training.""" 

130 coaches = [ 

131 coach for coach in resource.included if isinstance(coach, TrainingCoachResource) 

132 ] 

133 command = CreateTrainingCommand( 

134 start_date=resource.data.attributes.event.start_date, 

135 end_date=resource.data.attributes.event.end_date, 

136 active=resource.data.attributes.event.active, 

137 cancelled=resource.data.attributes.event.cancelled, 

138 texts=[ 

139 TextCommand( 

140 locale=text.locale, 

141 format=text.format, 

142 title=text.title, 

143 summary=text.original_summary or "", 

144 content=text.original_content or "", 

145 ) 

146 for text in resource.data.attributes.texts 

147 ], 

148 coaches=[ 

149 Coach( 

150 id=int(coach.id), 

151 head=coach.attributes.head, 

152 present=coach.attributes.present, 

153 payed=coach.attributes.payed, 

154 ) 

155 for coach in coaches 

156 ], 

157 teams=[int(team.id) for team in resource.data.relationships.teams.data], 

158 schedule=None 

159 if resource.data.relationships.schedule.data is None 

160 or resource.data.relationships.schedule.data.id is None 

161 else int(resource.data.relationships.schedule.data.id), 

162 location=resource.data.attributes.event.location, 

163 remark=resource.data.attributes.remark, 

164 ) 

165 

166 presenter = JsonApiTrainingPresenter() 

167 async with UnitOfWork(db): 

168 try: 

169 await CreateTraining( 

170 TrainingDbRepository(db), 

171 TrainingScheduleDbRepository(db), 

172 CoachDbRepository(db), 

173 TeamDbRepository(db), 

174 Owner(id=user.id, uuid=user.uuid, name=user.name), 

175 presenter, 

176 ).execute(command) 

177 except ValueError as ve: 

178 raise HTTPException( 

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

180 ) from ve 

181 

182 return presenter.get_document() 

183 

184 

185@router.patch( 

186 "/trainings/{training_id}", 

187 responses={status.HTTP_404_NOT_FOUND: {"description": "Training was not found."}}, 

188) 

189async def update_training( 

190 training_id: int, 

191 resource: TrainingDocument, 

192 db=Depends(create_database), 

193 user: UserEntity = Depends(get_current_user), 

194) -> TrainingDocument: 

195 """Update a training.""" 

196 coaches = [ 

197 coach for coach in resource.included if isinstance(coach, TrainingCoachResource) 

198 ] 

199 command = UpdateTrainingCommand( 

200 id=training_id, 

201 start_date=resource.data.attributes.event.start_date, 

202 end_date=resource.data.attributes.event.end_date, 

203 active=resource.data.attributes.event.active, 

204 cancelled=resource.data.attributes.event.cancelled, 

205 texts=[ 

206 TextCommand( 

207 locale=text.locale, 

208 format=text.format, 

209 title=text.title, 

210 summary=text.original_summary or "", 

211 content=text.original_content or "", 

212 ) 

213 for text in resource.data.attributes.texts 

214 ], 

215 coaches=[ 

216 Coach( 

217 id=int(coach.id), 

218 head=coach.attributes.head, 

219 present=coach.attributes.present, 

220 payed=coach.attributes.payed, 

221 ) 

222 for coach in coaches 

223 ], 

224 teams=[int(team.id) for team in resource.data.relationships.teams.data], 

225 schedule=None 

226 if resource.data.relationships.schedule.data is None 

227 else int(resource.data.relationships.schedule.data.id), 

228 location=resource.data.attributes.event.location, 

229 remark=resource.data.attributes.remark, 

230 ) 

231 

232 presenter = JsonApiTrainingPresenter() 

233 async with UnitOfWork(db): 

234 try: 

235 await UpdateTraining( 

236 TrainingDbRepository(db), 

237 TrainingScheduleDbRepository(db), 

238 CoachDbRepository(db), 

239 TeamDbRepository(db), 

240 Owner(id=user.id, uuid=user.uuid, name=user.name), 

241 presenter, 

242 ).execute(command) 

243 except TrainingNotFoundException as ex: 

244 raise HTTPException( 

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

246 ) from ex 

247 except ValueError as ve: 

248 raise HTTPException( 

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

250 ) from ve 

251 

252 return presenter.get_document() 

253 

254 

255@router.delete( 

256 "/trainings/{training_id}", 

257 responses={status.HTTP_404_NOT_FOUND: {"description": "Training was not found."}}, 

258) 

259async def delete_training( 

260 training_id: int, 

261 db=Depends(create_database), 

262 user: UserEntity = Depends(get_current_user), 

263) -> None: 

264 """Delete a training schedule.""" 

265 command = DeleteTrainingCommand(id=training_id) 

266 async with UnitOfWork(db): 

267 await DeleteTraining(TrainingDbRepository(db)).execute(command)