|
10 | 10 |
|
11 | 11 |
|
12 | 12 | from pydantic import BaseModel, ConfigDict |
13 | | -from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON |
| 13 | +from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON, or_, func, cast |
| 14 | + |
14 | 15 |
|
15 | 16 | from open_webui.utils.access_control import has_access |
16 | 17 |
|
@@ -85,7 +86,18 @@ class PromptAccessResponse(PromptUserResponse): |
85 | 86 | write_access: Optional[bool] = False |
86 | 87 |
|
87 | 88 |
|
| 89 | +class PromptListResponse(BaseModel): |
| 90 | + items: list[PromptUserResponse] |
| 91 | + total: int |
| 92 | + |
| 93 | + |
| 94 | +class PromptAccessListResponse(BaseModel): |
| 95 | + items: list[PromptAccessResponse] |
| 96 | + total: int |
| 97 | + |
| 98 | + |
88 | 99 | class PromptForm(BaseModel): |
| 100 | + |
89 | 101 | command: str |
90 | 102 | name: str # Changed from title |
91 | 103 | content: str |
@@ -227,7 +239,109 @@ def get_prompts_by_user_id( |
227 | 239 | or has_access(user_id, permission, prompt.access_control, user_group_ids) |
228 | 240 | ] |
229 | 241 |
|
| 242 | + def search_prompts( |
| 243 | + self, |
| 244 | + user_id: str, |
| 245 | + filter: dict = {}, |
| 246 | + skip: int = 0, |
| 247 | + limit: int = 30, |
| 248 | + db: Optional[Session] = None, |
| 249 | + ) -> PromptListResponse: |
| 250 | + with get_db_context(db) as db: |
| 251 | + from open_webui.models.users import User, UserModel |
| 252 | + |
| 253 | + # Join with User table for user filtering and sorting |
| 254 | + query = db.query(Prompt, User).outerjoin(User, User.id == Prompt.user_id) |
| 255 | + query = query.filter(Prompt.is_active == True) |
| 256 | + |
| 257 | + if filter: |
| 258 | + query_key = filter.get("query") |
| 259 | + if query_key: |
| 260 | + query = query.filter( |
| 261 | + or_( |
| 262 | + Prompt.name.ilike(f"%{query_key}%"), |
| 263 | + Prompt.command.ilike(f"%{query_key}%"), |
| 264 | + Prompt.content.ilike(f"%{query_key}%"), |
| 265 | + User.name.ilike(f"%{query_key}%"), |
| 266 | + User.email.ilike(f"%{query_key}%"), |
| 267 | + ) |
| 268 | + ) |
| 269 | + |
| 270 | + view_option = filter.get("view_option") |
| 271 | + if view_option == "created": |
| 272 | + query = query.filter(Prompt.user_id == user_id) |
| 273 | + elif view_option == "shared": |
| 274 | + query = query.filter(Prompt.user_id != user_id) |
| 275 | + |
| 276 | + # Apply access control filtering |
| 277 | + group_ids = filter.get("group_ids", []) |
| 278 | + filter_user_id = filter.get("user_id") |
| 279 | + |
| 280 | + if filter_user_id: |
| 281 | + # User must have access: owner OR public OR explicit access |
| 282 | + access_conditions = [ |
| 283 | + Prompt.user_id == filter_user_id, # Owner |
| 284 | + Prompt.access_control == None, # Public |
| 285 | + ] |
| 286 | + query = query.filter(or_(*access_conditions)) |
| 287 | + |
| 288 | + tag = filter.get("tag") |
| 289 | + if tag: |
| 290 | + # Search for tag in JSON array field |
| 291 | + like_pattern = f'%"{tag.lower()}"%' |
| 292 | + tags_text = func.lower(cast(Prompt.tags, String)) |
| 293 | + query = query.filter(tags_text.like(like_pattern)) |
| 294 | + |
| 295 | + order_by = filter.get("order_by") |
| 296 | + direction = filter.get("direction") |
| 297 | + |
| 298 | + if order_by == "name": |
| 299 | + if direction == "asc": |
| 300 | + query = query.order_by(Prompt.name.asc()) |
| 301 | + else: |
| 302 | + query = query.order_by(Prompt.name.desc()) |
| 303 | + elif order_by == "created_at": |
| 304 | + if direction == "asc": |
| 305 | + query = query.order_by(Prompt.created_at.asc()) |
| 306 | + else: |
| 307 | + query = query.order_by(Prompt.created_at.desc()) |
| 308 | + elif order_by == "updated_at": |
| 309 | + if direction == "asc": |
| 310 | + query = query.order_by(Prompt.updated_at.asc()) |
| 311 | + else: |
| 312 | + query = query.order_by(Prompt.updated_at.desc()) |
| 313 | + else: |
| 314 | + query = query.order_by(Prompt.updated_at.desc()) |
| 315 | + else: |
| 316 | + query = query.order_by(Prompt.updated_at.desc()) |
| 317 | + |
| 318 | + # Count BEFORE pagination |
| 319 | + total = query.count() |
| 320 | + |
| 321 | + if skip: |
| 322 | + query = query.offset(skip) |
| 323 | + if limit: |
| 324 | + query = query.limit(limit) |
| 325 | + |
| 326 | + items = query.all() |
| 327 | + |
| 328 | + prompts = [] |
| 329 | + for prompt, user in items: |
| 330 | + prompts.append( |
| 331 | + PromptUserResponse( |
| 332 | + **PromptModel.model_validate(prompt).model_dump(), |
| 333 | + user=( |
| 334 | + UserResponse(**UserModel.model_validate(user).model_dump()) |
| 335 | + if user |
| 336 | + else None |
| 337 | + ), |
| 338 | + ) |
| 339 | + ) |
| 340 | + |
| 341 | + return PromptListResponse(items=prompts, total=total) |
| 342 | + |
230 | 343 | def update_prompt_by_command( |
| 344 | + |
231 | 345 | self, |
232 | 346 | command: str, |
233 | 347 | form_data: PromptForm, |
|
0 commit comments