Files
opsxsql/backend/app/api/v1/endpoints/user.py
T
logan 66b09e4d85 feat: Phase 3 - AES encryption, SQL audit engine, audit logs (85 tests)
Phase 3.1: Instance password AES-256-GCM encryption
Phase 3.2: SQL audit rule engine (10 rules)
Phase 3.3: Auto-audit on ticket creation
Phase 3.4: Operation audit logs + GET /audit/logs
Tests: 44 -> 85 (41 new), Frontend: AuditLogsPage
2026-05-22 13:08:55 +08:00

117 lines
3.6 KiB
Python

from typing import Optional, List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.core.security import get_current_user, hash_password, require_role
from app.models.user import User
from app.schemas.user import UserCreate, UserUpdate, UserResponse
from app.services.audit_log_service import AuditLogService
router = APIRouter(prefix="/users", tags=["用户管理"])
@router.get("", response_model=List[UserResponse])
async def list_users(
role: Optional[str] = None,
is_active: Optional[bool] = None,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(require_role("admin")),
):
stmt = select(User).order_by(User.id)
if role:
stmt = stmt.where(User.role == role)
if is_active is not None:
stmt = stmt.where(User.is_active == is_active)
result = await db.execute(stmt)
return result.scalars().all()
@router.post("", response_model=UserResponse, status_code=201)
async def create_user(
data: UserCreate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(require_role("admin")),
):
exists = await db.execute(select(User).where(User.username == data.username))
if exists.scalar_one_or_none():
raise HTTPException(status_code=400, detail="用户名已存在")
user = User(
username=data.username,
display_name=data.display_name,
email=data.email,
phone=data.phone,
role=data.role,
hashed_password=hash_password(data.password),
)
db.add(user)
await db.flush()
await AuditLogService.log(
db, user_id=current_user.id, action="CREATE_USER",
target_type="user", target_id=user.id,
detail=f"创建用户: {data.username} ({data.role})",
)
await db.commit()
await db.refresh(user)
return user
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(
user_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(require_role("admin")),
):
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
return user
@router.put("/{user_id}", response_model=UserResponse)
async def update_user(
user_id: int,
data: UserUpdate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(require_role("admin")),
):
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
update_data = data.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(user, key, value)
await db.commit()
await db.refresh(user)
return user
@router.delete("/{user_id}")
async def delete_user(
user_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(require_role("admin")),
):
if user_id == current_user.id:
raise HTTPException(status_code=400, detail="不能删除自己")
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
await AuditLogService.log(
db, user_id=current_user.id, action="DELETE_USER",
target_type="user", target_id=user.id,
detail=f"删除用户: {user.username}",
)
await db.delete(user)
await db.commit()
return {"message": "用户已删除"}