2626)
2727from app .utils .crud import safe_delete_one , safe_insert , safe_update_one
2828
29+ # ponytail: cache scope stays "user"; Phase 2 (multi-member) must key invalidation on workspace_id.
30+
2931HISTORY_TRIM_BATCH_SIZE = 500
3032
3133
@@ -58,80 +60,80 @@ def _env_to_out(doc: dict[str, Any]) -> ApiClientEnvironmentOut:
5860
5961
6062@cached (ns = "api_client" , ttl = 300 , scope = "user" )
61- async def list_collections (* , uid : str ) -> list [ApiClientCollectionOut ]:
63+ async def list_collections (* , uid : str , workspace_id : str ) -> list [ApiClientCollectionOut ]:
6264 docs = await db_manager .find (
6365 API_CLIENT_COLLECTIONS ,
64- {"created_by " : uid },
66+ {"workspace_id " : workspace_id },
6567 {"_id" : 1 , "name" : 1 , "items" : 1 },
6668 sort = [("name" , 1 ), ("_id" , 1 )],
6769 )
6870 return [_collection_to_out (d ) for d in docs ]
6971
7072
71- async def create_collection (uid : str , body : ApiClientCollectionCreate ) -> ApiClientCollectionOut :
72- doc : dict [str , Any ] = {"created_by" : uid , "name" : body .name , "items" : []}
73+ async def create_collection (uid : str , workspace_id : str , body : ApiClientCollectionCreate ) -> ApiClientCollectionOut :
74+ doc : dict [str , Any ] = {"workspace_id" : workspace_id , " created_by" : uid , "name" : body .name , "items" : []}
7375 await safe_insert (API_CLIENT_COLLECTIONS , doc , name = "Collection" )
7476 await bump_version (ns = "api_client" , uid = uid )
7577 return _collection_to_out (doc )
7678
7779
78- async def patch_collection (uid : str , collection_id : str , body : ApiClientCollectionUpdate ) -> ApiClientCollectionOut :
80+ async def patch_collection (uid : str , workspace_id : str , collection_id : str , body : ApiClientCollectionUpdate ) -> ApiClientCollectionOut :
7981 oid = _parse_oid (collection_id , kind = "collection" )
8082 patch = body .model_dump (exclude_unset = True )
8183 if not patch :
82- doc = await db_manager .find_one (API_CLIENT_COLLECTIONS , {"_id" : oid , "created_by " : uid })
84+ doc = await db_manager .find_one (API_CLIENT_COLLECTIONS , {"_id" : oid , "workspace_id " : workspace_id })
8385 if not doc :
8486 raise HTTPException (status_code = status .HTTP_404_NOT_FOUND , detail = "Collection not found." )
8587 return _collection_to_out (doc )
8688 doc = await safe_update_one (
87- API_CLIENT_COLLECTIONS , {"_id" : oid , "created_by " : uid }, patch , name = "Collection"
89+ API_CLIENT_COLLECTIONS , {"_id" : oid , "workspace_id " : workspace_id }, patch , name = "Collection"
8890 )
8991 await bump_version (ns = "api_client" , uid = uid )
9092 return _collection_to_out (doc )
9193
9294
93- async def delete_collection (uid : str , collection_id : str ) -> None :
95+ async def delete_collection (uid : str , workspace_id : str , collection_id : str ) -> None :
9496 oid = _parse_oid (collection_id , kind = "collection" )
95- await safe_delete_one (API_CLIENT_COLLECTIONS , {"_id" : oid , "created_by " : uid }, name = "Collection" )
97+ await safe_delete_one (API_CLIENT_COLLECTIONS , {"_id" : oid , "workspace_id " : workspace_id }, name = "Collection" )
9698 await bump_version (ns = "api_client" , uid = uid )
9799
98100
99101@cached (ns = "api_client" , ttl = 300 , scope = "user" )
100- async def list_environments (* , uid : str ) -> list [ApiClientEnvironmentOut ]:
102+ async def list_environments (* , uid : str , workspace_id : str ) -> list [ApiClientEnvironmentOut ]:
101103 docs = await db_manager .find (
102104 API_CLIENT_ENVIRONMENTS ,
103- {"created_by " : uid },
105+ {"workspace_id " : workspace_id },
104106 {"_id" : 1 , "name" : 1 , "variables" : 1 },
105107 sort = [("name" , 1 ), ("_id" , 1 )],
106108 )
107109 return [_env_to_out (d ) for d in docs ]
108110
109111
110- async def create_environment (uid : str , body : ApiClientEnvironmentCreate ) -> ApiClientEnvironmentOut :
111- doc : dict [str , Any ] = {"created_by" : uid , "name" : body .name , "variables" : []}
112+ async def create_environment (uid : str , workspace_id : str , body : ApiClientEnvironmentCreate ) -> ApiClientEnvironmentOut :
113+ doc : dict [str , Any ] = {"workspace_id" : workspace_id , " created_by" : uid , "name" : body .name , "variables" : []}
112114 await safe_insert (API_CLIENT_ENVIRONMENTS , doc , name = "Environment" )
113115 await bump_version (ns = "api_client" , uid = uid )
114116 return _env_to_out (doc )
115117
116118
117- async def patch_environment (uid : str , environment_id : str , body : ApiClientEnvironmentUpdate ) -> ApiClientEnvironmentOut :
119+ async def patch_environment (uid : str , workspace_id : str , environment_id : str , body : ApiClientEnvironmentUpdate ) -> ApiClientEnvironmentOut :
118120 oid = _parse_oid (environment_id , kind = "environment" )
119121 patch = body .model_dump (exclude_unset = True )
120122 if not patch :
121- doc = await db_manager .find_one (API_CLIENT_ENVIRONMENTS , {"_id" : oid , "created_by " : uid })
123+ doc = await db_manager .find_one (API_CLIENT_ENVIRONMENTS , {"_id" : oid , "workspace_id " : workspace_id })
122124 if not doc :
123125 raise HTTPException (status_code = status .HTTP_404_NOT_FOUND , detail = "Environment not found." )
124126 return _env_to_out (doc )
125127 doc = await safe_update_one (
126- API_CLIENT_ENVIRONMENTS , {"_id" : oid , "created_by " : uid }, patch , name = "Environment"
128+ API_CLIENT_ENVIRONMENTS , {"_id" : oid , "workspace_id " : workspace_id }, patch , name = "Environment"
127129 )
128130 await bump_version (ns = "api_client" , uid = uid )
129131 return _env_to_out (doc )
130132
131133
132- async def delete_environment (uid : str , environment_id : str ) -> None :
134+ async def delete_environment (uid : str , workspace_id : str , environment_id : str ) -> None :
133135 oid = _parse_oid (environment_id , kind = "environment" )
134- await safe_delete_one (API_CLIENT_ENVIRONMENTS , {"_id" : oid , "created_by " : uid }, name = "Environment" )
136+ await safe_delete_one (API_CLIENT_ENVIRONMENTS , {"_id" : oid , "workspace_id " : workspace_id }, name = "Environment" )
135137 await bump_version (ns = "api_client" , uid = uid )
136138
137139
@@ -154,8 +156,8 @@ def _history_doc_to_out(doc: dict[str, Any]) -> ApiClientHistoryOut:
154156 )
155157
156158
157- async def trim_history (uid : str ) -> None :
158- filt = {"created_by " : uid }
159+ async def trim_history (uid : str , workspace_id : str ) -> None :
160+ filt = {"workspace_id " : workspace_id }
159161 stale_docs = await db_manager .find (
160162 API_CLIENT_HISTORY ,
161163 filt ,
@@ -167,20 +169,21 @@ async def trim_history(uid: str) -> None:
167169 if not stale_docs :
168170 return
169171 ids = [d ["_id" ] for d in stale_docs ]
170- await db_manager .delete_many (API_CLIENT_HISTORY , {"_id" : {"$in" : ids }, "created_by " : uid })
172+ await db_manager .delete_many (API_CLIENT_HISTORY , {"_id" : {"$in" : ids }, "workspace_id " : workspace_id })
171173 await bump_version (ns = "api_client" , uid = uid )
172174
173175
174176@cached (ns = "api_client" , ttl = 300 , scope = "user" )
175- async def list_history (* , uid : str , limit : int = HISTORY_MAX_ITEMS ) -> list [ApiClientHistoryOut ]:
177+ async def list_history (* , uid : str , workspace_id : str , limit : int = HISTORY_MAX_ITEMS ) -> list [ApiClientHistoryOut ]:
176178 lim = max (1 , min (limit , HISTORY_MAX_ITEMS ))
177- docs = await db_manager .find (API_CLIENT_HISTORY , {"created_by " : uid }, sort = [("timestamp" , - 1 )], limit = lim )
179+ docs = await db_manager .find (API_CLIENT_HISTORY , {"workspace_id " : workspace_id }, sort = [("timestamp" , - 1 )], limit = lim )
178180 return [_history_doc_to_out (d ) for d in docs ]
179181
180182
181- async def create_history (uid : str , body : ApiClientHistoryCreate ) -> ApiClientHistoryOut :
183+ async def create_history (uid : str , workspace_id : str , body : ApiClientHistoryCreate ) -> ApiClientHistoryOut :
182184 ts = body .timestamp if body .timestamp is not None else int (time .time () * 1000 )
183185 doc : dict [str , Any ] = {
186+ "workspace_id" : workspace_id ,
184187 "created_by" : uid ,
185188 "method" : body .method ,
186189 "url" : body .url ,
@@ -197,15 +200,15 @@ async def create_history(uid: str, body: ApiClientHistoryCreate) -> ApiClientHis
197200 return _history_doc_to_out (doc )
198201
199202
200- async def delete_history_entry (uid : str , entry_id : str ) -> None :
203+ async def delete_history_entry (uid : str , workspace_id : str , entry_id : str ) -> None :
201204 oid = _parse_oid (entry_id , kind = "history" )
202- await safe_delete_one (API_CLIENT_HISTORY , {"_id" : oid , "created_by " : uid }, name = "History entry" )
205+ await safe_delete_one (API_CLIENT_HISTORY , {"_id" : oid , "workspace_id " : workspace_id }, name = "History entry" )
203206 await bump_version (ns = "api_client" , uid = uid )
204207
205208
206- async def clear_history (uid : str ) -> None :
209+ async def clear_history (uid : str , workspace_id : str ) -> None :
207210 try :
208- await db_manager .delete_many (API_CLIENT_HISTORY , {"created_by " : uid })
211+ await db_manager .delete_many (API_CLIENT_HISTORY , {"workspace_id " : workspace_id })
209212 except PyMongoError as exc :
210213 raise HTTPException (
211214 status_code = status .HTTP_500_INTERNAL_SERVER_ERROR , detail = "Failed to clear history."
0 commit comments