From d5884f6d2cf98b6419fcc38e7fcdec7988195ec8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Mar 2026 11:32:34 +0000 Subject: [PATCH] fix(api): address code review feedback - logging, wildcard escaping, UX - Add exception logging in saved search error handlers - Escape SQL LIKE wildcards (%, _) in tags filter to prevent unintended matching - Improve UI alert message for empty filter save attempt Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- app/api/files.py | 4 +++- app/api/saved_searches.py | 9 ++++++--- app/views/files.py | 4 +++- frontend/templates/files.html | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/api/files.py b/app/api/files.py index 5cca3587..a8f8a240 100644 --- a/app/api/files.py +++ b/app/api/files.py @@ -143,7 +143,9 @@ def list_files_api( if tags: tag_list = [t.strip().lower() for t in tags.split(",") if t.strip()] for tag in tag_list: - query = query.filter(FileRecord.ai_metadata.ilike(f"%{tag}%")) + # Escape SQL LIKE wildcards to prevent unintended pattern matching + escaped_tag = tag.replace("%", r"\%").replace("_", r"\_") + query = query.filter(FileRecord.ai_metadata.ilike(f"%{escaped_tag}%")) # Apply status filter (before pagination for correct counts) query = apply_status_filter(query, db, status) diff --git a/app/api/saved_searches.py b/app/api/saved_searches.py index 2985e276..92caba31 100644 --- a/app/api/saved_searches.py +++ b/app/api/saved_searches.py @@ -182,8 +182,9 @@ def create_saved_search( db.add(saved_search) db.commit() db.refresh(saved_search) - except Exception: + except Exception as exc: db.rollback() + logger.exception(f"Failed to create saved search for user={user_id}: {exc}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to save search", @@ -254,8 +255,9 @@ def update_saved_search( try: db.commit() db.refresh(saved_search) - except Exception: + except Exception as exc: db.rollback() + logger.exception(f"Failed to update saved search id={search_id}, user={user_id}: {exc}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to update saved search", @@ -284,8 +286,9 @@ def delete_saved_search(search_id: int, request: Request, db: DbSession): try: db.delete(saved_search) db.commit() - except Exception: + except Exception as exc: db.rollback() + logger.exception(f"Failed to delete saved search id={search_id}, user={user_id}: {exc}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to delete saved search", diff --git a/app/views/files.py b/app/views/files.py index 0b7f96f4..a9b69a45 100644 --- a/app/views/files.py +++ b/app/views/files.py @@ -90,7 +90,9 @@ def files_page( if tags: tag_list = [t.strip().lower() for t in tags.split(",") if t.strip()] for tag in tag_list: - query = query.filter(FileRecord.ai_metadata.ilike(f"%{tag}%")) + # Escape SQL LIKE wildcards to prevent unintended pattern matching + escaped_tag = tag.replace("%", r"\%").replace("_", r"\_") + query = query.filter(FileRecord.ai_metadata.ilike(f"%{escaped_tag}%")) # Apply status filter (before pagination for correct counts) query = apply_status_filter(query, db, status) diff --git a/frontend/templates/files.html b/frontend/templates/files.html index d51b0e94..5a353155 100644 --- a/frontend/templates/files.html +++ b/frontend/templates/files.html @@ -1136,7 +1136,7 @@ if (val) filters[key] = val; }); if (Object.keys(filters).length === 0) { - alert('No filters to save. Apply some filters first.'); + alert('No filters to save. Please apply at least one filter (search, date, status, tags, etc.) before saving.'); return; } const name = prompt('Enter a name for this saved search:');