Coverage for src/kwai/api/v1/trainings/endpoints/trainings.py: 89%

74 statements  

« prev     ^ index     » next       coverage.py v7.6.10, 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 pydantic import BaseModel, Field 

7 

8from kwai.api.dependencies import create_database, get_current_user 

9from kwai.api.v1.trainings.schemas.training import TrainingDocument 

10from kwai.core.domain.use_case import TextCommand 

11from kwai.core.domain.value_objects.owner import Owner 

12from kwai.core.json_api import Meta, PaginationModel 

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

14from kwai.modules.training.coaches.coach_db_repository import CoachDbRepository 

15from kwai.modules.training.coaches.coach_repository import CoachNotFoundException 

16from kwai.modules.training.create_training import ( 

17 CreateTraining, 

18 CreateTrainingCommand, 

19) 

20from kwai.modules.training.delete_training import DeleteTraining, DeleteTrainingCommand 

21from kwai.modules.training.get_training import GetTraining, GetTrainingCommand 

22from kwai.modules.training.get_trainings import GetTrainings, GetTrainingsCommand 

23from kwai.modules.training.teams.team_db_repository import TeamDbRepository 

24from kwai.modules.training.training_command import Coach 

25from kwai.modules.training.trainings.training_db_repository import TrainingDbRepository 

26from kwai.modules.training.trainings.training_definition_db_repository import ( 

27 TrainingDefinitionDbRepository, 

28) 

29from kwai.modules.training.trainings.training_definition_repository import ( 

30 TrainingDefinitionNotFoundException, 

31) 

32from kwai.modules.training.trainings.training_repository import ( 

33 TrainingNotFoundException, 

34) 

35from kwai.modules.training.update_training import UpdateTraining, UpdateTrainingCommand 

36 

37 

38router = APIRouter() 

39 

40 

41class TrainingsFilterModel(BaseModel): 

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

43 

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

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

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

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

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

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

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

51 

52 

53@router.get( 

54 "/trainings", 

55 responses={ 

56 status.HTTP_404_NOT_FOUND: { 

57 "description": "Coach or Training definition was not found." 

58 } 

59 }, 

60) 

61async def get_trainings( 

62 pagination: PaginationModel = Depends(PaginationModel), 

63 trainings_filter: TrainingsFilterModel = Depends(TrainingsFilterModel), 

64 db=Depends(create_database), 

65) -> TrainingDocument: 

66 """Get all trainings.""" 

67 command = GetTrainingsCommand( 

68 offset=pagination.offset or 0, 

69 limit=pagination.limit, 

70 year=trainings_filter.year, 

71 month=trainings_filter.month, 

72 start=trainings_filter.start, 

73 end=trainings_filter.end, 

74 active=trainings_filter.active, 

75 coach=trainings_filter.coach, 

76 definition=trainings_filter.definition, 

77 ) 

78 

79 try: 

80 count, training_iterator = await GetTrainings( 

81 TrainingDbRepository(db), 

82 CoachDbRepository(db), 

83 TrainingDefinitionDbRepository(db), 

84 ).execute(command) 

85 except TrainingDefinitionNotFoundException as ex: 

86 raise HTTPException( 

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

88 ) from ex 

89 except CoachNotFoundException as ex: 

90 raise HTTPException( 

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

92 ) from ex 

93 

94 document: TrainingDocument = TrainingDocument( 

95 meta=Meta(count=count, offset=command.offset, limit=command.limit), data=[] 

96 ) 

97 async for training in training_iterator: 

98 document.merge(TrainingDocument.create(training)) 

99 

100 return document 

101 

102 

103@router.get( 

104 "/trainings/{training_id}", 

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

106) 

107async def get_training( 

108 training_id: int, 

109 db=Depends(create_database), 

110) -> TrainingDocument: 

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

112 command = GetTrainingCommand(id=training_id) 

113 

114 try: 

115 training = await GetTraining(TrainingDbRepository(db)).execute(command) 

116 except TrainingNotFoundException as ex: 

117 raise HTTPException( 

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

119 ) from ex 

120 

121 return TrainingDocument.create(training) 

122 

123 

124@router.post( 

125 "/trainings", 

126 status_code=status.HTTP_201_CREATED, 

127) 

128async def create_training( 

129 resource: TrainingDocument, 

130 db=Depends(create_database), 

131 user: UserEntity = Depends(get_current_user), 

132) -> TrainingDocument: 

133 """Create a new training.""" 

134 command = CreateTrainingCommand( 

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

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

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

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

139 texts=[ 

140 TextCommand( 

141 locale=text.locale, 

142 format=text.format, 

143 title=text.title, 

144 summary=text.original_summary, 

145 content=text.original_content, 

146 ) 

147 for text in resource.data.attributes.texts 

148 ], 

149 coaches=[ 

150 Coach( 

151 id=int(coach.id), 

152 head=coach.head, 

153 present=coach.present, 

154 payed=coach.payed, 

155 ) 

156 for coach in resource.data.attributes.coaches 

157 ], 

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

159 definition=None 

160 if resource.data.relationships.definition.data is None 

161 else resource.data.relationships.definition.data.id, 

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

163 remark=resource.data.attributes.remark, 

164 ) 

165 

166 try: 

167 training = await CreateTraining( 

168 TrainingDbRepository(db), 

169 TrainingDefinitionDbRepository(db), 

170 CoachDbRepository(db), 

171 TeamDbRepository(db), 

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

173 ).execute(command) 

174 except ValueError as ve: 

175 raise HTTPException( 

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

177 ) from ve 

178 

179 return TrainingDocument.create(training) 

180 

181 

182@router.patch( 

183 "/trainings/{training_id}", 

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

185) 

186async def update_training( 

187 training_id: int, 

188 resource: TrainingDocument, 

189 db=Depends(create_database), 

190 user: UserEntity = Depends(get_current_user), 

191) -> TrainingDocument: 

192 """Update a training.""" 

193 command = UpdateTrainingCommand( 

194 id=training_id, 

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

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

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

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

199 texts=[ 

200 TextCommand( 

201 locale=text.locale, 

202 format=text.format, 

203 title=text.title, 

204 summary=text.original_summary, 

205 content=text.original_content, 

206 ) 

207 for text in resource.data.attributes.texts 

208 ], 

209 coaches=[ 

210 Coach( 

211 id=int(coach.id), 

212 head=coach.head, 

213 present=coach.present, 

214 payed=coach.payed, 

215 ) 

216 for coach in resource.data.attributes.coaches 

217 ], 

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

219 definition=None 

220 if resource.data.relationships.definition.data is None 

221 else resource.data.relationships.definition.data.id, 

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

223 remark=resource.data.attributes.remark, 

224 ) 

225 

226 try: 

227 training = await UpdateTraining( 

228 TrainingDbRepository(db), 

229 TrainingDefinitionDbRepository(db), 

230 CoachDbRepository(db), 

231 TeamDbRepository(db), 

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

233 ).execute(command) 

234 except TrainingNotFoundException as ex: 

235 raise HTTPException( 

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

237 ) from ex 

238 except ValueError as ve: 

239 raise HTTPException( 

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

241 ) from ve 

242 

243 return TrainingDocument.create(training) 

244 

245 

246@router.delete( 

247 "/trainings/{training_id}", 

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

249) 

250async def delete_training( 

251 training_id: int, 

252 db=Depends(create_database), 

253 user: UserEntity = Depends(get_current_user), 

254) -> None: 

255 """Delete a training definition.""" 

256 command = DeleteTrainingCommand(id=training_id) 

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