186 lines
5.9 KiB
Python
186 lines
5.9 KiB
Python
"""
|
||
管理员 API:用户管理
|
||
"""
|
||
from fastapi import APIRouter, HTTPException, Depends, status
|
||
from pydantic import BaseModel
|
||
from typing import Optional, List
|
||
from datetime import datetime, timezone, timedelta
|
||
from app.core.supabase import get_supabase
|
||
from app.core.deps import get_current_admin
|
||
from loguru import logger
|
||
|
||
router = APIRouter(prefix="/api/admin", tags=["管理"])
|
||
|
||
|
||
class UserListItem(BaseModel):
|
||
id: str
|
||
phone: str
|
||
username: Optional[str]
|
||
role: str
|
||
is_active: bool
|
||
expires_at: Optional[str]
|
||
created_at: str
|
||
|
||
|
||
class ActivateRequest(BaseModel):
|
||
expires_days: Optional[int] = None # 授权天数,None 表示永久
|
||
|
||
|
||
@router.get("/users", response_model=List[UserListItem])
|
||
async def list_users(admin: dict = Depends(get_current_admin)):
|
||
"""获取所有用户列表"""
|
||
try:
|
||
supabase = get_supabase()
|
||
result = supabase.table("users").select("*").order("created_at", desc=True).execute()
|
||
|
||
return [
|
||
UserListItem(
|
||
id=u["id"],
|
||
phone=u["phone"],
|
||
username=u.get("username"),
|
||
role=u["role"],
|
||
is_active=u["is_active"],
|
||
expires_at=u.get("expires_at"),
|
||
created_at=u["created_at"]
|
||
)
|
||
for u in result.data
|
||
]
|
||
except Exception as e:
|
||
logger.error(f"获取用户列表失败: {e}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail="获取用户列表失败"
|
||
)
|
||
|
||
|
||
@router.post("/users/{user_id}/activate")
|
||
async def activate_user(
|
||
user_id: str,
|
||
request: ActivateRequest,
|
||
admin: dict = Depends(get_current_admin)
|
||
):
|
||
"""
|
||
激活用户
|
||
|
||
Args:
|
||
user_id: 用户 ID
|
||
request.expires_days: 授权天数 (None 表示永久)
|
||
"""
|
||
try:
|
||
supabase = get_supabase()
|
||
|
||
# 计算过期时间
|
||
expires_at = None
|
||
if request.expires_days:
|
||
expires_at = (datetime.now(timezone.utc) + timedelta(days=request.expires_days)).isoformat()
|
||
|
||
# 更新用户
|
||
result = supabase.table("users").update({
|
||
"is_active": True,
|
||
"role": "user",
|
||
"expires_at": expires_at
|
||
}).eq("id", user_id).execute()
|
||
|
||
if not result.data:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail="用户不存在"
|
||
)
|
||
|
||
logger.info(f"管理员 {admin['phone']} 激活用户 {user_id}, 有效期: {request.expires_days or '永久'} 天")
|
||
|
||
return {
|
||
"success": True,
|
||
"message": f"用户已激活,有效期: {request.expires_days or '永久'} 天"
|
||
}
|
||
except HTTPException:
|
||
raise
|
||
except Exception as e:
|
||
logger.error(f"激活用户失败: {e}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail="激活用户失败"
|
||
)
|
||
|
||
|
||
@router.post("/users/{user_id}/deactivate")
|
||
async def deactivate_user(
|
||
user_id: str,
|
||
admin: dict = Depends(get_current_admin)
|
||
):
|
||
"""停用用户"""
|
||
try:
|
||
supabase = get_supabase()
|
||
|
||
# 不能停用管理员
|
||
user_result = supabase.table("users").select("role").eq("id", user_id).single().execute()
|
||
if user_result.data and user_result.data["role"] == "admin":
|
||
raise HTTPException(
|
||
status_code=status.HTTP_400_BAD_REQUEST,
|
||
detail="不能停用管理员账号"
|
||
)
|
||
|
||
# 更新用户
|
||
result = supabase.table("users").update({
|
||
"is_active": False
|
||
}).eq("id", user_id).execute()
|
||
|
||
# 清除用户 session
|
||
supabase.table("user_sessions").delete().eq("user_id", user_id).execute()
|
||
|
||
logger.info(f"管理员 {admin['phone']} 停用用户 {user_id}")
|
||
|
||
return {"success": True, "message": "用户已停用"}
|
||
except HTTPException:
|
||
raise
|
||
except Exception as e:
|
||
logger.error(f"停用用户失败: {e}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail="停用用户失败"
|
||
)
|
||
|
||
|
||
@router.post("/users/{user_id}/extend")
|
||
async def extend_user(
|
||
user_id: str,
|
||
request: ActivateRequest,
|
||
admin: dict = Depends(get_current_admin)
|
||
):
|
||
"""延长用户授权期限"""
|
||
try:
|
||
supabase = get_supabase()
|
||
|
||
if not request.expires_days:
|
||
# 设为永久
|
||
expires_at = None
|
||
else:
|
||
# 获取当前过期时间
|
||
user_result = supabase.table("users").select("expires_at").eq("id", user_id).single().execute()
|
||
user = user_result.data
|
||
|
||
if user and user.get("expires_at"):
|
||
current_expires = datetime.fromisoformat(user["expires_at"].replace("Z", "+00:00"))
|
||
base_time = max(current_expires, datetime.now(timezone.utc))
|
||
else:
|
||
base_time = datetime.now(timezone.utc)
|
||
|
||
expires_at = (base_time + timedelta(days=request.expires_days)).isoformat()
|
||
|
||
result = supabase.table("users").update({
|
||
"expires_at": expires_at
|
||
}).eq("id", user_id).execute()
|
||
|
||
logger.info(f"管理员 {admin['phone']} 延长用户 {user_id} 授权 {request.expires_days or '永久'} 天")
|
||
|
||
return {
|
||
"success": True,
|
||
"message": f"授权已延长 {request.expires_days or '永久'} 天"
|
||
}
|
||
except Exception as e:
|
||
logger.error(f"延长授权失败: {e}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail="延长授权失败"
|
||
)
|