refactor: Auth/User 路由重构 + 新增 user_api 前端接口

- auth_router 移除旧的 get_admin_user,统一使用 auth_middleware
- user_router 新增 get_users 接口
- 前端新增 user_api.js,更新 index.js 导出
This commit is contained in:
Wenjie Zhang 2026-05-24 00:46:25 +08:00
parent 5f61d8f8c5
commit d2859ab8cd
4 changed files with 37 additions and 24 deletions

View File

@ -1,5 +1,4 @@
import re
import uuid
from yuxi.utils import logger
from fastapi import APIRouter, Body, Depends, HTTPException, Request, status, UploadFile, File
@ -23,7 +22,7 @@ from server.utils.auth_middleware import (
from server.utils.auth_utils import AuthUtils
from server.utils.user_utils import generate_unique_uid, validate_username, is_valid_phone_number
from server.utils.common_utils import log_operation
from yuxi.storage.minio import aupload_file_to_minio
from yuxi.services.upload_utils import upload_image_to_minio
from yuxi.utils.datetime_utils import utc_now_naive
# OIDC 认证相关导入
@ -843,35 +842,22 @@ async def upload_user_avatar(
file: UploadFile = File(...), current_user: User = Depends(get_required_user), db: AsyncSession = Depends(get_db)
):
"""上传用户头像"""
# 检查文件类型
if not file.content_type or not file.content_type.startswith("image/"):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="只能上传图片文件")
# 检查文件大小5MB限制
file_size = 0
file_content = await file.read()
file_size = len(file_content)
if file_size > 5 * 1024 * 1024: # 5MB
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="文件大小不能超过5MB")
try:
# 获取文件扩展名
file_extension = file.filename.split(".")[-1].lower() if file.filename and "." in file.filename else "jpg"
avatar_url = await upload_image_to_minio(
file,
object_prefix=f"avatar/{current_user.id}",
max_size_bytes=5 * 1024 * 1024,
too_large_message="文件大小不能超过5MB",
)
# 上传到MinIO
file_name = f"avatar/{current_user.id}/{uuid.uuid4()}.{file_extension}"
avatar_url = await aupload_file_to_minio("public", file_name, file_content)
# 更新用户头像
current_user.avatar = avatar_url
await db.commit()
# 记录操作
await log_operation(db, current_user.id, "上传头像", f"更新头像: {avatar_url}")
return {"success": True, "avatar_url": avatar_url, "message": "头像上传成功"}
except ValueError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
except Exception as e:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"头像上传失败: {str(e)}")

View File

@ -5,13 +5,14 @@ import re
import secrets
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile, status
from pydantic import BaseModel, Field
from sqlalchemy import func, select
from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.ext.asyncio import AsyncSession
from server.utils.auth_middleware import get_db, get_required_user
from yuxi.services.upload_utils import upload_image_to_minio
from yuxi.storage.postgres.models_business import APIKey, AgentEnv, User
from yuxi.utils.datetime_utils import coerce_any_to_utc_datetime, format_utc_datetime, utc_now_naive
@ -21,6 +22,7 @@ ENV_KEY_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
MAX_ENV_COUNT = 200
MAX_ENV_KEY_LENGTH = 128
MAX_ENV_VALUE_LENGTH = 32768
MAX_USER_IMAGE_SIZE_BYTES = 5 * 1024 * 1024
def generate_api_key() -> tuple[str, str, str]:
@ -71,6 +73,21 @@ class AgentEnvResponse(BaseModel):
updated_at: str | None = None
@user_router.post("/upload-image", response_model=dict)
async def upload_user_image(file: UploadFile = File(...), current_user: User = Depends(get_required_user)):
try:
image_url = await upload_image_to_minio(
file,
object_prefix=f"images/{current_user.uid}",
max_size_bytes=MAX_USER_IMAGE_SIZE_BYTES,
too_large_message="图片大小不能超过 5MB",
)
except ValueError as exc:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
return {"success": True, "image_url": image_url, "url": image_url}
def validate_agent_env(env: dict[str, Any]) -> dict[str, str]:
if len(env) > MAX_ENV_COUNT:
raise HTTPException(status_code=400, detail=f"环境变量数量不能超过 {MAX_ENV_COUNT}")

View File

@ -16,6 +16,7 @@ export * from './skill_api' // Skills API
export * from './subagent_api' // SubAgent API
export * from './tool_api' // 工具 API
export * from './mention_api' // 提及搜索 API
export * from './user_api' // 用户资源 API
// 导出基础工具函数
export {

9
web/src/apis/user_api.js Normal file
View File

@ -0,0 +1,9 @@
import { apiPost } from './base'
export const userApi = {
uploadImage: (file) => {
const formData = new FormData()
formData.append('file', file)
return apiPost('/api/user/upload-image', formData)
}
}