feat: add proper HTTP status codes to all API error responses
- 217 error returns across 18 route files + api.py now use JSONResponse with appropriate HTTP status codes instead of returning HTTP 200 - Status code distribution: 500 (121), 400 (39), 503 (28), 404 (24), 409 (3), 502 (2) - Fixed language.py tuple-return bug (was serializing as JSON array) - Fixed bare except clauses in bipolar_mode.py and voice.py - Body-level error schemas preserved (status/error + success/error patterns) so web UI continues working without changes - chat.py (SSE) unchanged: errors sent within stream protocol - All 170 tests pass
This commit is contained in:
@@ -5,6 +5,7 @@ import os
|
||||
import json
|
||||
from typing import List
|
||||
from fastapi import APIRouter, UploadFile, File, Form
|
||||
from fastapi.responses import JSONResponse
|
||||
import discord
|
||||
import globals
|
||||
from routes.models import CustomPromptRequest
|
||||
@@ -25,7 +26,7 @@ async def send_custom_prompt_dm(user_id: str, req: CustomPromptRequest):
|
||||
user_id_int = int(user_id)
|
||||
user = globals.client.get_user(user_id_int)
|
||||
if not user:
|
||||
return {"status": "error", "message": f"User {user_id} not found"}
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": f"User {user_id} not found"})
|
||||
|
||||
# Use the LLM query function for DM context
|
||||
from utils.llm import query_llama
|
||||
@@ -47,9 +48,9 @@ async def send_custom_prompt_dm(user_id: str, req: CustomPromptRequest):
|
||||
return {"status": "ok", "message": f"Custom DM prompt queued for user {user_id}"}
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": "Invalid user ID format"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid user ID format"})
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Error: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
|
||||
|
||||
|
||||
@router.post("/dm/{user_id}/manual")
|
||||
@@ -65,7 +66,7 @@ async def send_manual_message_dm(
|
||||
user_id_int = int(user_id)
|
||||
user = globals.client.get_user(user_id_int)
|
||||
if not user:
|
||||
return {"status": "error", "message": f"User {user_id} not found"}
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": f"User {user_id} not found"})
|
||||
|
||||
# Read file content immediately before the request closes
|
||||
file_data = []
|
||||
@@ -78,7 +79,7 @@ async def send_manual_message_dm(
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to read file {file.filename}: {e}")
|
||||
return {"status": "error", "message": f"Failed to read file {file.filename}: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to read file {file.filename}: {e}"})
|
||||
|
||||
async def send_dm_message_and_files():
|
||||
try:
|
||||
@@ -120,9 +121,9 @@ async def send_manual_message_dm(
|
||||
return {"status": "ok", "message": f"Manual DM message queued for user {user_id}"}
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": "Invalid user ID format"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid user ID format"})
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Error: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
|
||||
|
||||
|
||||
# ========== DM Logging Endpoints ==========
|
||||
@@ -134,7 +135,7 @@ def get_dm_users():
|
||||
users = dm_logger.get_all_dm_users()
|
||||
return {"status": "ok", "users": users}
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Failed to get DM users: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to get DM users: {e}"})
|
||||
|
||||
|
||||
@router.get("/dms/users/{user_id}")
|
||||
@@ -146,9 +147,9 @@ def get_dm_user_conversation(user_id: str):
|
||||
summary = dm_logger.get_user_conversation_summary(user_id_int)
|
||||
return {"status": "ok", "summary": summary}
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Failed to get user conversation: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to get user conversation: {e}"})
|
||||
|
||||
|
||||
@router.get("/dms/users/{user_id}/conversations")
|
||||
@@ -180,10 +181,10 @@ def get_dm_conversations(user_id: str, limit: int = 50):
|
||||
|
||||
return {"status": "ok", "conversations": conversations}
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get conversations for user {user_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to get conversations: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to get conversations: {e}"})
|
||||
|
||||
|
||||
@router.get("/dms/users/{user_id}/search")
|
||||
@@ -195,9 +196,9 @@ def search_dm_conversations(user_id: str, query: str, limit: int = 10):
|
||||
results = dm_logger.search_user_conversations(user_id_int, query, limit)
|
||||
return {"status": "ok", "results": results}
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Failed to search conversations: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to search conversations: {e}"})
|
||||
|
||||
|
||||
@router.get("/dms/users/{user_id}/export")
|
||||
@@ -209,9 +210,9 @@ def export_dm_conversation(user_id: str, format: str = "json"):
|
||||
export_path = dm_logger.export_user_conversation(user_id_int, format)
|
||||
return {"status": "ok", "export_path": export_path, "format": format}
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Failed to export conversation: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to export conversation: {e}"})
|
||||
|
||||
|
||||
@router.delete("/dms/users/{user_id}")
|
||||
@@ -225,11 +226,11 @@ def delete_dm_user_logs(user_id: str):
|
||||
os.remove(log_file)
|
||||
return {"status": "ok", "message": f"Deleted DM logs for user {user_id}"}
|
||||
else:
|
||||
return {"status": "error", "message": f"No DM logs found for user {user_id}"}
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": f"No DM logs found for user {user_id}"})
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": f"Failed to delete DM logs: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to delete DM logs: {e}"})
|
||||
|
||||
|
||||
# ========== User Blocking & DM Management ==========
|
||||
@@ -242,7 +243,7 @@ def get_blocked_users():
|
||||
return {"status": "ok", "blocked_users": blocked_users}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get blocked users: {e}")
|
||||
return {"status": "error", "message": f"Failed to get blocked users: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to get blocked users: {e}"})
|
||||
|
||||
|
||||
@router.post("/dms/users/{user_id}/block")
|
||||
@@ -261,13 +262,13 @@ def block_user(user_id: str):
|
||||
logger.info(f"User {user_id} ({username}) blocked")
|
||||
return {"status": "ok", "message": f"User {username} has been blocked"}
|
||||
else:
|
||||
return {"status": "error", "message": f"User {username} is already blocked"}
|
||||
return JSONResponse(status_code=409, content={"status": "error", "message": f"User {username} is already blocked"})
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to block user {user_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to block user: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to block user: {e}"})
|
||||
|
||||
|
||||
@router.post("/dms/users/{user_id}/unblock")
|
||||
@@ -281,13 +282,13 @@ def unblock_user(user_id: str):
|
||||
logger.info(f"User {user_id} unblocked")
|
||||
return {"status": "ok", "message": f"User has been unblocked"}
|
||||
else:
|
||||
return {"status": "error", "message": f"User is not blocked"}
|
||||
return JSONResponse(status_code=409, content={"status": "error", "message": f"User is not blocked"})
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to unblock user {user_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to unblock user: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to unblock user: {e}"})
|
||||
|
||||
|
||||
@router.post("/dms/users/{user_id}/conversations/{conversation_id}/delete")
|
||||
@@ -308,10 +309,10 @@ def delete_conversation(user_id: str, conversation_id: str):
|
||||
return {"status": "ok", "message": "Message deletion queued (will delete from both Discord and logs)"}
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to queue conversation deletion {conversation_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to delete conversation: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to delete conversation: {e}"})
|
||||
|
||||
|
||||
@router.post("/dms/users/{user_id}/conversations/delete-all")
|
||||
@@ -331,10 +332,10 @@ def delete_all_conversations(user_id: str):
|
||||
return {"status": "ok", "message": "Bulk deletion queued (will delete all Miku messages from Discord and clear logs)"}
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to queue bulk conversation deletion for user {user_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to delete conversations: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to delete conversations: {e}"})
|
||||
|
||||
|
||||
@router.post("/dms/users/{user_id}/delete-completely")
|
||||
@@ -348,13 +349,13 @@ def delete_user_completely(user_id: str):
|
||||
logger.info(f"Completely deleted user {user_id}")
|
||||
return {"status": "ok", "message": "User data deleted completely"}
|
||||
else:
|
||||
return {"status": "error", "message": "No user data found"}
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": "No user data found"})
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to completely delete user {user_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to delete user: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to delete user: {e}"})
|
||||
|
||||
|
||||
# ========== DM Interaction Analysis Endpoints ==========
|
||||
@@ -366,7 +367,7 @@ def run_dm_analysis():
|
||||
from utils.dm_interaction_analyzer import dm_analyzer
|
||||
|
||||
if dm_analyzer is None:
|
||||
return {"status": "error", "message": "DM Analyzer not initialized. Set OWNER_USER_ID environment variable."}
|
||||
return JSONResponse(status_code=503, content={"status": "error", "message": "DM Analyzer not initialized. Set OWNER_USER_ID environment variable."})
|
||||
|
||||
# Schedule analysis in Discord's event loop
|
||||
async def run_analysis():
|
||||
@@ -377,7 +378,7 @@ def run_dm_analysis():
|
||||
return {"status": "ok", "message": "DM analysis started"}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to run DM analysis: {e}")
|
||||
return {"status": "error", "message": f"Failed to run DM analysis: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to run DM analysis: {e}"})
|
||||
|
||||
|
||||
@router.post("/dms/users/{user_id}/analyze")
|
||||
@@ -387,7 +388,7 @@ def analyze_user_interaction(user_id: str):
|
||||
from utils.dm_interaction_analyzer import dm_analyzer
|
||||
|
||||
if dm_analyzer is None:
|
||||
return {"status": "error", "message": "DM Analyzer not initialized. Set OWNER_USER_ID environment variable."}
|
||||
return JSONResponse(status_code=503, content={"status": "error", "message": "DM Analyzer not initialized. Set OWNER_USER_ID environment variable."})
|
||||
|
||||
user_id_int = int(user_id)
|
||||
|
||||
@@ -401,10 +402,10 @@ def analyze_user_interaction(user_id: str):
|
||||
return {"status": "ok", "message": f"Analysis started for user {user_id}", "reported": True}
|
||||
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to analyze user {user_id}: {e}")
|
||||
return {"status": "error", "message": f"Failed to analyze user: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to analyze user: {e}"})
|
||||
|
||||
|
||||
@router.get("/dms/analysis/reports")
|
||||
@@ -432,7 +433,7 @@ def get_analysis_reports(limit: int = 20):
|
||||
return {"status": "ok", "reports": reports}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get reports: {e}")
|
||||
return {"status": "error", "message": f"Failed to get reports: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to get reports: {e}"})
|
||||
|
||||
|
||||
@router.get("/dms/analysis/reports/{user_id}")
|
||||
@@ -461,7 +462,7 @@ def get_user_reports(user_id: str, limit: int = 10):
|
||||
|
||||
return {"status": "ok", "reports": reports}
|
||||
except ValueError:
|
||||
return {"status": "error", "message": f"Invalid user ID format: {user_id}"}
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": f"Invalid user ID format: {user_id}"})
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get user reports: {e}")
|
||||
return {"status": "error", "message": f"Failed to get user reports: {e}"}
|
||||
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to get user reports: {e}"})
|
||||
|
||||
Reference in New Issue
Block a user