1- from typing import Any , Dict , Optional
1+ from typing import Any
22
33KNOWLEDGE_FILTERS_INDEX_NAME = "knowledge_filters"
44
@@ -7,15 +7,23 @@ class KnowledgeFilterService:
77 def __init__ (self , session_manager = None ):
88 self .session_manager = session_manager
99
10+ def _user_client (self , user_id : str = None , jwt_token : str = None ):
11+ return self .session_manager .get_user_opensearch_client (user_id , jwt_token )
12+
13+ def _write_client (self , user_id : str = None , jwt_token : str = None ):
14+ # OpenSearch rejects write requests on indices protected by filter-level
15+ # DLS. The app enforces ownership/visibility with the scoped client, then
16+ # performs trusted writes with the admin client.
17+ from config .settings import clients
18+
19+ return clients .opensearch or self ._user_client (user_id , jwt_token )
20+
1021 async def create_knowledge_filter (
11- self , filter_doc : Dict [str , Any ], user_id : str = None , jwt_token : str = None
12- ) -> Dict [str , Any ]:
22+ self , filter_doc : dict [str , Any ], user_id : str = None , jwt_token : str = None
23+ ) -> dict [str , Any ]:
1324 """Create a new knowledge filter"""
1425 try :
15- # Get user's OpenSearch client with JWT for OIDC auth
16- opensearch_client = self .session_manager .get_user_opensearch_client (
17- user_id , jwt_token
18- )
26+ opensearch_client = self ._write_client (user_id , jwt_token )
1927
2028 # Index the knowledge filter document
2129 result = await opensearch_client .index (
@@ -40,13 +48,10 @@ async def create_knowledge_filter(
4048
4149 async def search_knowledge_filters (
4250 self , query : str , user_id : str = None , jwt_token : str = None , limit : int = 20
43- ) -> Dict [str , Any ]:
51+ ) -> dict [str , Any ]:
4452 """Search for knowledge filters by name, description, or query content"""
4553 try :
46- # Get user's OpenSearch client with JWT for OIDC auth
47- opensearch_client = self .session_manager .get_user_opensearch_client (
48- user_id , jwt_token
49- )
54+ opensearch_client = self ._user_client (user_id , jwt_token )
5055
5156 if query .strip ():
5257 # Search across name, description, and query_data fields
@@ -109,17 +114,12 @@ async def search_knowledge_filters(
109114
110115 async def get_knowledge_filter (
111116 self , filter_id : str , user_id : str = None , jwt_token : str = None
112- ) -> Dict [str , Any ]:
117+ ) -> dict [str , Any ]:
113118 """Get a specific knowledge filter by ID"""
114119 try :
115- # Get user's OpenSearch client with JWT for OIDC auth
116- opensearch_client = self .session_manager .get_user_opensearch_client (
117- user_id , jwt_token
118- )
120+ opensearch_client = self ._user_client (user_id , jwt_token )
119121
120- result = await opensearch_client .get (
121- index = KNOWLEDGE_FILTERS_INDEX_NAME , id = filter_id
122- )
122+ result = await opensearch_client .get (index = KNOWLEDGE_FILTERS_INDEX_NAME , id = filter_id )
123123
124124 if result .get ("found" ):
125125 knowledge_filter = result ["_source" ]
@@ -133,16 +133,17 @@ async def get_knowledge_filter(
133133 async def update_knowledge_filter (
134134 self ,
135135 filter_id : str ,
136- updates : Dict [str , Any ],
136+ updates : dict [str , Any ],
137137 user_id : str = None ,
138138 jwt_token : str = None ,
139- ) -> Dict [str , Any ]:
139+ ) -> dict [str , Any ]:
140140 """Update an existing knowledge filter"""
141141 try :
142- # Get user's OpenSearch client with JWT for OIDC auth
143- opensearch_client = self .session_manager .get_user_opensearch_client (
144- user_id , jwt_token
145- )
142+ existing = await self .get_knowledge_filter (filter_id , user_id , jwt_token )
143+ if not existing .get ("success" ):
144+ return existing
145+
146+ opensearch_client = self ._write_client (user_id , jwt_token )
146147
147148 # Update the document
148149 result = await opensearch_client .update (
@@ -159,10 +160,10 @@ async def update_knowledge_filter(
159160 await opensearch_client .indices .refresh (index = KNOWLEDGE_FILTERS_INDEX_NAME )
160161 except Exception :
161162 pass
162- updated_doc = await opensearch_client . get (
163- index = KNOWLEDGE_FILTERS_INDEX_NAME , id = filter_id
164- )
165- return {"success" : True , "filter " : updated_doc [ "_source" ] }
163+ updated_doc = await self . get_knowledge_filter ( filter_id , user_id , jwt_token )
164+ if updated_doc . get ( "success" ):
165+ return updated_doc
166+ return {"success" : False , "error " : "Failed to read updated knowledge filter" }
166167 else :
167168 return {"success" : False , "error" : "Failed to update knowledge filter" }
168169
@@ -171,13 +172,17 @@ async def update_knowledge_filter(
171172
172173 async def delete_knowledge_filter (
173174 self , filter_id : str , user_id : str = None , jwt_token : str = None
174- ) -> Dict [str , Any ]:
175+ ) -> dict [str , Any ]:
175176 """Delete a knowledge filter"""
176177 try :
177- # Get user's OpenSearch client with JWT for OIDC auth
178- opensearch_client = self .session_manager .get_user_opensearch_client (
179- user_id , jwt_token
180- )
178+ existing = await self .get_knowledge_filter (filter_id , user_id , jwt_token )
179+ if not existing .get ("success" ):
180+ return {
181+ "success" : False ,
182+ "error" : "Knowledge filter not found or access denied" ,
183+ }
184+
185+ opensearch_client = self ._write_client (user_id , jwt_token )
181186
182187 result = await opensearch_client .delete (
183188 index = KNOWLEDGE_FILTERS_INDEX_NAME ,
@@ -219,20 +224,14 @@ async def delete_knowledge_filter(
219224 async def add_subscription (
220225 self ,
221226 filter_id : str ,
222- subscription_data : Dict [str , Any ],
227+ subscription_data : dict [str , Any ],
223228 user_id : str = None ,
224229 jwt_token : str = None ,
225- ) -> Dict [str , Any ]:
230+ ) -> dict [str , Any ]:
226231 """Add a subscription to a knowledge filter"""
227232 try :
228- opensearch_client = self .session_manager .get_user_opensearch_client (
229- user_id , jwt_token
230- )
231-
232233 # Get the current filter document
233- filter_result = await self .get_knowledge_filter (
234- filter_id , user_id , jwt_token
235- )
234+ filter_result = await self .get_knowledge_filter (filter_id , user_id , jwt_token )
236235 if not filter_result .get ("success" ):
237236 return filter_result
238237
@@ -246,12 +245,11 @@ async def add_subscription(
246245 update_body = {
247246 "doc" : {
248247 "subscriptions" : subscriptions ,
249- "updated_at" : subscription_data [
250- "created_at"
251- ], # Use the same timestamp
248+ "updated_at" : subscription_data ["created_at" ], # Use the same timestamp
252249 }
253250 }
254251
252+ opensearch_client = self ._write_client (user_id , jwt_token )
255253 result = await opensearch_client .update (
256254 index = KNOWLEDGE_FILTERS_INDEX_NAME ,
257255 id = filter_id ,
@@ -273,17 +271,11 @@ async def remove_subscription(
273271 subscription_id : str ,
274272 user_id : str = None ,
275273 jwt_token : str = None ,
276- ) -> Dict [str , Any ]:
274+ ) -> dict [str , Any ]:
277275 """Remove a subscription from a knowledge filter"""
278276 try :
279- opensearch_client = self .session_manager .get_user_opensearch_client (
280- user_id , jwt_token
281- )
282-
283277 # Get the current filter document
284- filter_result = await self .get_knowledge_filter (
285- filter_id , user_id , jwt_token
286- )
278+ filter_result = await self .get_knowledge_filter (filter_id , user_id , jwt_token )
287279 if not filter_result .get ("success" ):
288280 return filter_result
289281
@@ -292,9 +284,7 @@ async def remove_subscription(
292284 # Remove subscription from the subscriptions array
293285 subscriptions = filter_doc .get ("subscriptions" , [])
294286 updated_subscriptions = [
295- sub
296- for sub in subscriptions
297- if sub .get ("subscription_id" ) != subscription_id
287+ sub for sub in subscriptions if sub .get ("subscription_id" ) != subscription_id
298288 ]
299289
300290 if len (updated_subscriptions ) == len (subscriptions ):
@@ -310,6 +300,7 @@ async def remove_subscription(
310300 }
311301 }
312302
303+ opensearch_client = self ._write_client (user_id , jwt_token )
313304 result = await opensearch_client .update (
314305 index = KNOWLEDGE_FILTERS_INDEX_NAME , id = filter_id , body = update_body
315306 )
@@ -324,12 +315,10 @@ async def remove_subscription(
324315
325316 async def get_filter_subscriptions (
326317 self , filter_id : str , user_id : str = None , jwt_token : str = None
327- ) -> Dict [str , Any ]:
318+ ) -> dict [str , Any ]:
328319 """Get all subscriptions for a knowledge filter"""
329320 try :
330- filter_result = await self .get_knowledge_filter (
331- filter_id , user_id , jwt_token
332- )
321+ filter_result = await self .get_knowledge_filter (filter_id , user_id , jwt_token )
333322 if not filter_result .get ("success" ):
334323 return filter_result
335324
0 commit comments