Coverage for src/kwai/api/v1/teams/api.py: 85%
96 statements
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2024-01-01 00:00 +0000
1"""Module that defines the teams API."""
3from typing import Annotated
5from fastapi import APIRouter, Depends, HTTPException, Query, status
6from pydantic import BaseModel, Field
8from kwai.api.dependencies import create_database, get_current_user
9from kwai.api.v1.teams.presenters import (
10 JsonApiMembersPresenter,
11 JsonApiTeamMemberPresenter,
12 JsonApiTeamMembersPresenter,
13 JsonApiTeamPresenter,
14 JsonApiTeamsPresenter,
15)
16from kwai.api.v1.teams.schemas import TeamDocument, TeamMemberDocument
17from kwai.core.db.database import Database
18from kwai.core.db.uow import UnitOfWork
19from kwai.core.json_api import PaginationModel
20from kwai.modules.identity.users.user import UserEntity
21from kwai.modules.teams.create_team import CreateTeam, CreateTeamCommand
22from kwai.modules.teams.create_team_member import (
23 CreateTeamMember,
24 CreateTeamMemberCommand,
25)
26from kwai.modules.teams.delete_team import DeleteTeam, DeleteTeamCommand
27from kwai.modules.teams.domain.team import TeamMemberAlreadyExistException
28from kwai.modules.teams.get_members import GetMembers, GetMembersCommand
29from kwai.modules.teams.get_team import GetTeam, GetTeamCommand
30from kwai.modules.teams.get_teams import GetTeams, GetTeamsCommand
31from kwai.modules.teams.repositories.member_db_repository import MemberDbRepository
32from kwai.modules.teams.repositories.member_repository import MemberNotFoundException
33from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository
34from kwai.modules.teams.update_team import UpdateTeam, UpdateTeamCommand
35from kwai.modules.training.teams.team_repository import TeamNotFoundException
38router = APIRouter(tags=["teams"])
41@router.get("/teams")
42async def get_teams(
43 database: Annotated[Database, Depends(create_database)],
44) -> TeamDocument:
45 """Get all teams of the club."""
46 presenter = JsonApiTeamsPresenter()
47 command = GetTeamsCommand(offset=0, limit=0)
48 await GetTeams(TeamDbRepository(database), presenter).execute(command)
49 return presenter.get_document()
52class TeamMemberFilterModel(BaseModel):
53 """Define the JSON:API filter for team members."""
55 team: str | None = Field(Query(default=None, alias="filter[team]"))
58@router.get("/teams/members")
59async def get_members(
60 database: Annotated[Database, Depends(create_database)],
61 pagination: Annotated[PaginationModel, Depends(PaginationModel)],
62 team_filter: Annotated[TeamMemberFilterModel, Depends(TeamMemberFilterModel)],
63) -> TeamMemberDocument:
64 """Get all members that can be part of a team."""
65 presenter = JsonApiMembersPresenter()
66 if team_filter.team is not None:
67 if ":" in team_filter.team:
68 operand, team_id = team_filter.team.split(":")
69 if operand not in ("eq", "noteq"):
70 raise HTTPException(
71 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
72 detail="Invalid operand",
73 )
74 if not team_id.isdigit():
75 raise HTTPException(
76 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
77 detail="Invalid team id",
78 )
80 command = GetMembersCommand(
81 team_id=int(team_id),
82 in_team=operand == "eq",
83 offset=pagination.offset,
84 limit=pagination.limit,
85 )
86 else:
87 if team_filter.team.isdigit():
88 command = GetMembersCommand(
89 team_id=int(team_filter.team),
90 offset=pagination.offset,
91 limit=pagination.limit,
92 )
93 else:
94 raise HTTPException(
95 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
96 detail="Invalid team id",
97 )
98 else:
99 command = GetMembersCommand(offset=pagination.offset, limit=pagination.limit)
100 await GetMembers(MemberDbRepository(database), presenter).execute(command)
101 return presenter.get_document()
104@router.get("/teams/{id}")
105async def get_team(
106 id: int,
107 database: Annotated[Database, Depends(create_database)],
108) -> TeamDocument:
109 """Get the team with the given id."""
110 presenter = JsonApiTeamPresenter()
111 command = GetTeamCommand(id=id)
112 await GetTeam(TeamDbRepository(database), presenter).execute(command)
113 return presenter.get_document()
116@router.post("/teams", status_code=status.HTTP_201_CREATED)
117async def create_team(
118 resource: TeamDocument,
119 database: Annotated[Database, Depends(create_database)],
120 user: Annotated[UserEntity, Depends(get_current_user)],
121) -> TeamDocument:
122 """Create a new team."""
123 command = CreateTeamCommand(
124 name=resource.data.attributes.name,
125 active=resource.data.attributes.active,
126 remark=resource.data.attributes.remark,
127 )
128 team_presenter = JsonApiTeamPresenter()
129 async with UnitOfWork(database):
130 await CreateTeam(TeamDbRepository(database), team_presenter).execute(command)
131 return team_presenter.get_document()
134@router.patch(
135 "/teams/{id}",
136 status_code=status.HTTP_200_OK,
137 responses={status.HTTP_404_NOT_FOUND: {"description": "Team not found"}},
138)
139async def update_team(
140 id: int,
141 resource: TeamDocument,
142 database: Annotated[Database, Depends(create_database)],
143 user: Annotated[UserEntity, Depends(get_current_user)],
144) -> TeamDocument:
145 """Update an existing team."""
146 command = UpdateTeamCommand(
147 id=id,
148 name=resource.data.attributes.name,
149 active=resource.data.attributes.active,
150 remark=resource.data.attributes.remark,
151 )
152 team_presenter = JsonApiTeamPresenter()
153 async with UnitOfWork(database):
154 await UpdateTeam(TeamDbRepository(database), team_presenter).execute(command)
155 return team_presenter.get_document()
158@router.delete(
159 "/teams/{id}",
160 status_code=status.HTTP_200_OK,
161 responses={status.HTTP_404_NOT_FOUND: {"description": "Team not found"}},
162)
163async def delete_team(
164 id: int,
165 database: Annotated[Database, Depends(create_database)],
166 user: Annotated[UserEntity, Depends(get_current_user)],
167):
168 """Delete the team with the given id."""
169 command = DeleteTeamCommand(id=id)
171 try:
172 async with UnitOfWork(database):
173 await DeleteTeam(TeamDbRepository(database)).execute(command)
174 except TeamNotFoundException as ex:
175 raise HTTPException(
176 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)
177 ) from ex
180@router.get("/teams/{id}/members")
181async def get_team_members(
182 id: int,
183 database: Annotated[Database, Depends(create_database)],
184) -> TeamMemberDocument:
185 """Get the members of the team with the given id."""
186 presenter = JsonApiTeamMembersPresenter()
187 command = GetTeamCommand(id=id)
188 await GetTeam(TeamDbRepository(database), presenter).execute(command)
189 return presenter.get_document()
192@router.post("/teams/{id}/members", status_code=status.HTTP_201_CREATED)
193async def create_team_member(
194 id: int,
195 resource: TeamMemberDocument,
196 database: Annotated[Database, Depends(create_database)],
197) -> TeamMemberDocument:
198 """Add a member to the team with the given id."""
199 presenter = JsonApiTeamMemberPresenter()
200 command = CreateTeamMemberCommand(
201 team_id=id,
202 member_id=resource.data.id,
203 active=resource.data.attributes.active,
204 )
205 try:
206 async with UnitOfWork(database):
207 await CreateTeamMember(
208 TeamDbRepository(database), MemberDbRepository(database), presenter
209 ).execute(command)
210 return presenter.get_document()
211 except TeamNotFoundException as ex:
212 raise HTTPException(
213 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)
214 ) from ex
215 except MemberNotFoundException as ex:
216 raise HTTPException(
217 status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)
218 ) from ex
219 except TeamMemberAlreadyExistException as ex:
220 raise HTTPException(
221 status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex)
222 ) from ex