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