246 lines
7.5 KiB
Python
246 lines
7.5 KiB
Python
"""用户管理路由(超管)"""
|
|
|
|
from datetime import UTC, datetime
|
|
from uuid import uuid4
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.exc import IntegrityError
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..database import get_db
|
|
from ..deps import require_permission
|
|
from ..models import Account, AuditLog, HuyaAccount, User
|
|
from ..permissions import PERMISSIONS, get_user_permissions
|
|
from ..schemas import UserCreate, UserInfo, UserRename, UserUpdate
|
|
from ..security import hash_password
|
|
|
|
router = APIRouter(prefix="/api/users", tags=["用户管理"])
|
|
|
|
|
|
@router.get("", response_model=list[UserInfo])
|
|
def list_users(
|
|
db: Session = Depends(get_db),
|
|
_: User = Depends(require_permission("user:view")),
|
|
):
|
|
users = db.query(User).filter(User.deleted_at.is_(None)).order_by(User.id).all()
|
|
result = []
|
|
for u in users:
|
|
result.append(
|
|
UserInfo(
|
|
id=u.id,
|
|
username=u.username,
|
|
role=u.role,
|
|
is_active=u.is_active,
|
|
remark=u.remark or "",
|
|
created_at=u.created_at,
|
|
permissions=get_user_permissions(u),
|
|
custom_permissions=u.custom_permissions,
|
|
)
|
|
)
|
|
return result
|
|
|
|
|
|
@router.post("", response_model=UserInfo)
|
|
def create_user(
|
|
req: UserCreate,
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("user:create")),
|
|
):
|
|
if db.query(User).filter(User.username == req.username).first():
|
|
raise HTTPException(status_code=400, detail="用户名已存在")
|
|
|
|
user = User(
|
|
username=req.username,
|
|
password_hash=hash_password(req.password),
|
|
role=req.role,
|
|
remark=req.remark,
|
|
is_active=True,
|
|
)
|
|
db.add(user)
|
|
db.commit()
|
|
db.refresh(user)
|
|
|
|
db.add(
|
|
AuditLog(
|
|
user_id=current.id,
|
|
username=current.username,
|
|
action="user:create",
|
|
target=user.username,
|
|
)
|
|
)
|
|
db.commit()
|
|
|
|
return UserInfo(
|
|
id=user.id,
|
|
username=user.username,
|
|
role=user.role,
|
|
is_active=user.is_active,
|
|
remark=user.remark or "",
|
|
permissions=get_user_permissions(user),
|
|
custom_permissions=user.custom_permissions,
|
|
)
|
|
|
|
|
|
@router.put("/{user_id}", response_model=UserInfo)
|
|
def update_user(
|
|
user_id: int,
|
|
req: UserUpdate,
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("user:edit")),
|
|
):
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
if user.deleted_at is not None:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
|
|
if req.password:
|
|
user.password_hash = hash_password(req.password)
|
|
if req.role is not None:
|
|
user.role = req.role
|
|
if req.is_active is not None:
|
|
user.is_active = req.is_active
|
|
if req.remark is not None:
|
|
user.remark = req.remark
|
|
if "custom_permissions" in req.model_fields_set:
|
|
user.custom_permissions = req.custom_permissions
|
|
|
|
db.commit()
|
|
db.refresh(user)
|
|
|
|
db.add(
|
|
AuditLog(
|
|
user_id=current.id,
|
|
username=current.username,
|
|
action="user:edit",
|
|
target=user.username,
|
|
)
|
|
)
|
|
db.commit()
|
|
|
|
return UserInfo(
|
|
id=user.id,
|
|
username=user.username,
|
|
role=user.role,
|
|
is_active=user.is_active,
|
|
remark=user.remark or "",
|
|
permissions=get_user_permissions(user),
|
|
custom_permissions=user.custom_permissions,
|
|
)
|
|
|
|
|
|
@router.patch("/{user_id}/username", response_model=UserInfo)
|
|
def rename_user(
|
|
user_id: int,
|
|
req: UserRename,
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("user:rename")),
|
|
):
|
|
"""仅变更用户名,保留用户 ID 和全部关联业务数据。"""
|
|
user = db.query(User).filter(User.id == user_id, User.deleted_at.is_(None)).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
|
|
username = req.username.strip()
|
|
if len(username) < 2:
|
|
raise HTTPException(status_code=400, detail="用户名至少 2 个字符")
|
|
if username == user.username:
|
|
return UserInfo(
|
|
id=user.id,
|
|
username=user.username,
|
|
role=user.role,
|
|
is_active=user.is_active,
|
|
remark=user.remark or "",
|
|
permissions=get_user_permissions(user),
|
|
custom_permissions=user.custom_permissions,
|
|
)
|
|
if db.query(User.id).filter(User.username == username).first():
|
|
raise HTTPException(status_code=400, detail="用户名已存在")
|
|
|
|
old_username = user.username
|
|
user.username = username
|
|
db.add(
|
|
AuditLog(
|
|
user_id=current.id,
|
|
username=current.username,
|
|
action="user:rename",
|
|
target=f"{old_username} -> {username}",
|
|
)
|
|
)
|
|
try:
|
|
db.commit()
|
|
except IntegrityError as exc:
|
|
db.rollback()
|
|
raise HTTPException(status_code=400, detail="用户名已存在") from exc
|
|
db.refresh(user)
|
|
return UserInfo(
|
|
id=user.id,
|
|
username=user.username,
|
|
role=user.role,
|
|
is_active=user.is_active,
|
|
remark=user.remark or "",
|
|
permissions=get_user_permissions(user),
|
|
custom_permissions=user.custom_permissions,
|
|
)
|
|
|
|
|
|
@router.delete("/{user_id}")
|
|
def delete_user(
|
|
user_id: int,
|
|
db: Session = Depends(get_db),
|
|
current: User = Depends(require_permission("user:delete")),
|
|
):
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
if user.deleted_at is not None:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
if user.role == "super_admin":
|
|
raise HTTPException(status_code=400, detail="不能删除超级管理员")
|
|
if user.id == current.id:
|
|
raise HTTPException(status_code=400, detail="不能删除当前登录用户")
|
|
|
|
# 保留任务与审计记录的创建者 ID,避免删除用户时破坏历史数据。
|
|
released_accounts = (
|
|
db.query(Account)
|
|
.filter(Account.assigned_to == user.id)
|
|
.update({Account.assigned_to: None}, synchronize_session=False)
|
|
)
|
|
released_huya_accounts = (
|
|
db.query(HuyaAccount)
|
|
.filter(HuyaAccount.assigned_to == user.id)
|
|
.update({HuyaAccount.assigned_to: None}, synchronize_session=False)
|
|
)
|
|
deleted_username = user.username
|
|
db.add(
|
|
AuditLog(
|
|
user_id=current.id,
|
|
username=current.username,
|
|
action="user:delete",
|
|
target=deleted_username,
|
|
)
|
|
)
|
|
user.is_active = False
|
|
user.deleted_at = datetime.now(UTC)
|
|
user.deleted_username = deleted_username
|
|
# 释放用户名供新用户使用,同时不改变历史任务通过 user.id 保存的归属。
|
|
user.username = f"deleted-{user.id}-{uuid4().hex[:12]}"
|
|
db.commit()
|
|
return {
|
|
"message": "已删除",
|
|
"success": True,
|
|
"released_accounts": released_accounts,
|
|
"released_huya_accounts": released_huya_accounts,
|
|
}
|
|
|
|
|
|
@router.get("/permissions/list")
|
|
def list_permissions(_: User = Depends(require_permission("user:assign_permissions"))):
|
|
"""返回所有可用权限点及角色默认权限映射。"""
|
|
from ..permissions import ROLE_PERMISSIONS
|
|
|
|
return {
|
|
"permissions": PERMISSIONS,
|
|
"role_permissions": ROLE_PERMISSIONS,
|
|
}
|