Coverage for api/endpoints/misc/clients.py: 49%
65 statements
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-10 03:02 +0300
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-10 03:02 +0300
1from typing import Annotated
3import motor
4from database.updater import remove_client_from_deps
5from exceptions import NoAccessHTTPError, NotFoundHTTPError
6from fastapi import APIRouter, Depends
7from handlers.authorization.check_role import has_role
8from handlers.authorization.company_employee_access import (
9 get_assigned_clients_ids,
10)
11from handlers.grabbers.clients import clients_grabber
12from handlers.misc.clients import (
13 assign_manager_to_client,
14 on_assign_subsidiary_to_client,
15 on_client_revoke_manager,
16 on_create_client,
17 on_get_clients_managers,
18 on_patch_client,
19 on_revoke_subsidiary,
20)
21from keycloak import idp
22from mongodb import clients_col, cm_clients_col, subsidiaries_clients_col
23from sotrans_models.models._base import InsertByOIDModel, InsertByUUIDModel
24from sotrans_models.models._mongo import PydanticObjectIdPath
25from sotrans_models.models.misc.client import (
26 AssignedToClientResponse,
27 ClientCreateModel,
28 ClientDBModel,
29 ClientUpdateModel,
30)
31from sotrans_models.models.responses import ErrorRepr, GenericGetListResponse
32from sotrans_models.models.roles import SotransRole
33from sotrans_models.models.users import (
34 SotransOIDCUserModel,
35 SotransUserDBModel,
36)
37from starlette import status
38from utils.data_grabber import (
39 BaseGetListQueryParams,
40 BaseGetOneQueryParams,
41 adjust_search_query,
42)
43from utils.helper import etag_detalizer
45clients_router = APIRouter(
46 prefix="/clients",
47 tags=["clients"],
48)
50clients_assignment_router = APIRouter(
51 prefix="/clients",
52 tags=["managers_clients_assignment"],
53)
56@clients_router.post("", status_code=status.HTTP_201_CREATED)
57async def create_client(
58 client: ClientCreateModel,
59 _: Annotated[
60 SotransOIDCUserModel,
61 Depends(
62 idp.get_current_user(
63 required_role_names=[SotransRole.company_director]
64 )
65 ),
66 ],
67) -> ClientDBModel:
68 return await on_create_client(client)
71@clients_router.patch("/{client_id}")
72async def change_client_data(
73 client_id: PydanticObjectIdPath,
74 client: ClientUpdateModel,
75 _: Annotated[
76 SotransOIDCUserModel,
77 Depends(
78 idp.get_current_user(
79 required_role_names=[SotransRole.company_director]
80 )
81 ),
82 ],
83) -> ClientDBModel:
84 return await on_patch_client(client_id, client)
87@clients_router.delete(
88 "/{client_id}",
89 responses={204: {"description": "No content"}},
90 status_code=204,
91)
92async def remove_client(
93 client_id: PydanticObjectIdPath,
94 _: Annotated[
95 SotransOIDCUserModel,
96 Depends(
97 idp.get_current_user(
98 required_role_names=[SotransRole.company_director]
99 )
100 ),
101 ],
102 resource_with_etag: ClientUpdateModel | None = None,
103):
104 clients_motor_col: motor.MotorCollection = (
105 clients_grabber.collection.collection
106 )
107 etag_q = (
108 {"etag": resource_with_etag.etag}
109 if resource_with_etag is not None
110 else {}
111 )
112 deletion = await clients_motor_col.delete_one({"_id": client_id} | etag_q)
113 if deletion.deleted_count == 0:
114 await etag_detalizer(clients_col, etag_q, {"_id": client_id})
115 raise NotFoundHTTPError("клиент")
116 await subsidiaries_clients_col.collection.update_many(
117 {}, {"$pull": {"clients_ids": client_id}}
118 )
119 await cm_clients_col.collection.update_many(
120 {}, {"$pull": {"clients_ids": client_id}}
121 )
122 await remove_client_from_deps(client_id)
125@clients_router.get("/{client_id}", responses={404: {"model": ErrorRepr}})
126async def clients_details(
127 client_id: PydanticObjectIdPath,
128 user: Annotated[
129 SotransOIDCUserModel,
130 Depends(
131 idp.get_current_user(
132 required_role_names=[SotransRole.company_manager]
133 )
134 ),
135 ],
136 params: BaseGetOneQueryParams = Depends(),
137) -> ClientDBModel:
138 if not has_role(user, SotransRole.company_director):
139 assigned = await get_assigned_clients_ids(user)
140 if client_id not in assigned:
141 raise NoAccessHTTPError("клиент не назначен")
142 return await clients_grabber.get_one(client_id, params=params)
145@clients_router.get("")
146async def get_clients_list(
147 user: Annotated[
148 SotransOIDCUserModel,
149 Depends(
150 idp.get_current_user(
151 required_role_names=[SotransRole.company_manager]
152 )
153 ),
154 ],
155 params: BaseGetListQueryParams = Depends(),
156) -> GenericGetListResponse[ClientDBModel]:
157 if not has_role(user, SotransRole.company_director):
158 assigned_clients = await get_assigned_clients_ids(user)
159 params.where = adjust_search_query(
160 params.where,
161 "id",
162 {str(ci) for ci in assigned_clients},
163 )
164 return await clients_grabber.get_list(params=params)
167# /-----------------------------------------------------------------------/
168# below assignment routes are placed
169# /-----------------------------------------------------------------------/
172@clients_assignment_router.put(
173 "/{client_id}/assign", status_code=status.HTTP_201_CREATED
174)
175async def assign_to_client(
176 client_id: PydanticObjectIdPath,
177 assignee: InsertByOIDModel | InsertByUUIDModel,
178 _: Annotated[
179 SotransOIDCUserModel,
180 Depends(
181 idp.get_current_user(
182 required_role_names=[SotransRole.company_director]
183 )
184 ),
185 ],
186) -> GenericGetListResponse[SotransUserDBModel] | AssignedToClientResponse:
187 if isinstance(assignee, InsertByOIDModel):
188 return await on_assign_subsidiary_to_client(assignee.id, client_id)
189 return await assign_manager_to_client(client_id, assignee.id)
192@clients_assignment_router.delete(
193 "/{client_id}/revoke", status_code=status.HTTP_204_NO_CONTENT
194)
195async def revoke_from_client(
196 client_id: PydanticObjectIdPath,
197 assignee: InsertByOIDModel | InsertByUUIDModel,
198 _: Annotated[
199 SotransOIDCUserModel,
200 Depends(
201 idp.get_current_user(
202 required_role_names=[SotransRole.company_director]
203 )
204 ),
205 ],
206):
207 if isinstance(assignee, InsertByOIDModel):
208 return await on_revoke_subsidiary(assignee.id, client_id)
209 await on_client_revoke_manager(client_id, assignee.id)
212@clients_assignment_router.get("/{client_id}/assign")
213async def get_clients_assigned(
214 client_id: PydanticObjectIdPath,
215 _: Annotated[
216 SotransOIDCUserModel,
217 Depends(
218 idp.get_current_user(
219 required_role_names=[SotransRole.company_logistician]
220 )
221 ),
222 ],
223) -> GenericGetListResponse[SotransUserDBModel]:
224 return await on_get_clients_managers(client_id)