# app/api/admin.py from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import JSONResponse from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import text from ..dependencies.auth import get_current_user from ..models.user import User from ..database import get_async_db router = APIRouter(prefix="/admin", tags=["admin"]) @router.get("/database/tables") async def get_database_tables( db: AsyncSession = Depends(get_async_db), current_user: User = Depends(get_current_user) ): """获取所有表(需要管理员权限)""" if not current_user.is_superuser: raise HTTPException(status_code=403, detail="需要管理员权限") try: # 使用 SQLAlchemy 执行原生 SQL result = db.execute(text(""" SELECT name, type, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name; """)) tables = [] for row in result: tables.append({ "name": row[0], "type": row[1], "sql": row[2] }) return JSONResponse(content={"tables": tables}) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.get("/database/table/{table_name}") async def get_table_data( table_name: str, limit: int = 100, db: AsyncSession = Depends(get_async_db), current_user: User = Depends(get_current_user) ): """获取表数据(需要管理员权限)""" if not current_user.is_superuser: raise HTTPException(status_code=403, detail="需要管理员权限") try: # 先验证表存在且可访问 result = db.execute(text(f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';")) if not result.fetchone(): raise HTTPException(status_code=404, detail="表不存在") # 获取表结构 columns_result = db.execute(text(f"PRAGMA table_info({table_name});")) columns = [] for row in columns_result: columns.append({ "cid": row[0], "name": row[1], "type": row[2], "notnull": bool(row[3]), "default_value": row[4], "pk": bool(row[5]) }) # 获取数据 data_result = db.execute(text(f"SELECT * FROM {table_name} LIMIT {limit};")) # 获取列名 column_names = [desc[0] for desc in data_result.cursor.description] # 获取数据行 rows = [] for row in data_result: row_dict = {} for i, value in enumerate(row): # 处理特殊类型(如 datetime) if hasattr(value, 'isoformat'): row_dict[column_names[i]] = value.isoformat() else: row_dict[column_names[i]] = value rows.append(row_dict) # 统计总数 count_result = db.execute(text(f"SELECT COUNT(*) FROM {table_name};")) total_count = count_result.scalar() return JSONResponse(content={ "table": table_name, "columns": columns, "data": rows, "total_count": total_count, "showing": len(rows) }) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @router.post("/database/query") async def execute_custom_query( query: str, db: AsyncSession = Depends(get_async_db), current_user: User = Depends(get_current_user) ): """执行自定义查询(需要管理员权限,生产环境请谨慎)""" if not current_user.is_superuser: raise HTTPException(status_code=403, detail="需要管理员权限") # 安全限制:不允许修改操作 query_lower = query.strip().lower() dangerous_keywords = ["drop", "delete", "update", "insert", "alter", "truncate"] if any(keyword in query_lower for keyword in dangerous_keywords): raise HTTPException(status_code=400, detail="只允许SELECT查询") try: result = db.execute(text(query)) # 如果是查询语句 if query_lower.startswith("select"): # 获取列名 column_names = [desc[0] for desc in result.cursor.description] # 获取数据 rows = [] for row in result: row_dict = {} for i, value in enumerate(row): if hasattr(value, 'isoformat'): row_dict[column_names[i]] = value.isoformat() else: row_dict[column_names[i]] = value rows.append(row_dict) return JSONResponse(content={ "query": query, "columns": column_names, "data": rows, "row_count": len(rows) }) else: # 非查询语句 db.commit() return JSONResponse(content={ "query": query, "affected_rows": result.rowcount, "message": "执行成功" }) except Exception as e: raise HTTPException(status_code=500, detail=str(e))