| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- # 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))
|