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:
parent
5f61d8f8c5
commit
d2859ab8cd
@ -1,5 +1,4 @@
|
|||||||
import re
|
import re
|
||||||
import uuid
|
|
||||||
from yuxi.utils import logger
|
from yuxi.utils import logger
|
||||||
|
|
||||||
from fastapi import APIRouter, Body, Depends, HTTPException, Request, status, UploadFile, File
|
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.auth_utils import AuthUtils
|
||||||
from server.utils.user_utils import generate_unique_uid, validate_username, is_valid_phone_number
|
from server.utils.user_utils import generate_unique_uid, validate_username, is_valid_phone_number
|
||||||
from server.utils.common_utils import log_operation
|
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
|
from yuxi.utils.datetime_utils import utc_now_naive
|
||||||
|
|
||||||
# OIDC 认证相关导入
|
# 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)
|
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:
|
try:
|
||||||
# 获取文件扩展名
|
avatar_url = await upload_image_to_minio(
|
||||||
file_extension = file.filename.split(".")[-1].lower() if file.filename and "." in file.filename else "jpg"
|
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
|
current_user.avatar = avatar_url
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|
||||||
# 记录操作
|
|
||||||
await log_operation(db, current_user.id, "上传头像", f"更新头像: {avatar_url}")
|
await log_operation(db, current_user.id, "上传头像", f"更新头像: {avatar_url}")
|
||||||
|
|
||||||
return {"success": True, "avatar_url": avatar_url, "message": "头像上传成功"}
|
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:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"头像上传失败: {str(e)}")
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"头像上传失败: {str(e)}")
|
||||||
|
|
||||||
|
|||||||
@ -5,13 +5,14 @@ import re
|
|||||||
import secrets
|
import secrets
|
||||||
from typing import Any
|
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 pydantic import BaseModel, Field
|
||||||
from sqlalchemy import func, select
|
from sqlalchemy import func, select
|
||||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from server.utils.auth_middleware import get_db, get_required_user
|
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.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
|
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_COUNT = 200
|
||||||
MAX_ENV_KEY_LENGTH = 128
|
MAX_ENV_KEY_LENGTH = 128
|
||||||
MAX_ENV_VALUE_LENGTH = 32768
|
MAX_ENV_VALUE_LENGTH = 32768
|
||||||
|
MAX_USER_IMAGE_SIZE_BYTES = 5 * 1024 * 1024
|
||||||
|
|
||||||
|
|
||||||
def generate_api_key() -> tuple[str, str, str]:
|
def generate_api_key() -> tuple[str, str, str]:
|
||||||
@ -71,6 +73,21 @@ class AgentEnvResponse(BaseModel):
|
|||||||
updated_at: str | None = None
|
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]:
|
def validate_agent_env(env: dict[str, Any]) -> dict[str, str]:
|
||||||
if len(env) > MAX_ENV_COUNT:
|
if len(env) > MAX_ENV_COUNT:
|
||||||
raise HTTPException(status_code=400, detail=f"环境变量数量不能超过 {MAX_ENV_COUNT} 个")
|
raise HTTPException(status_code=400, detail=f"环境变量数量不能超过 {MAX_ENV_COUNT} 个")
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export * from './skill_api' // Skills API
|
|||||||
export * from './subagent_api' // SubAgent API
|
export * from './subagent_api' // SubAgent API
|
||||||
export * from './tool_api' // 工具 API
|
export * from './tool_api' // 工具 API
|
||||||
export * from './mention_api' // 提及搜索 API
|
export * from './mention_api' // 提及搜索 API
|
||||||
|
export * from './user_api' // 用户资源 API
|
||||||
|
|
||||||
// 导出基础工具函数
|
// 导出基础工具函数
|
||||||
export {
|
export {
|
||||||
|
|||||||
9
web/src/apis/user_api.js
Normal file
9
web/src/apis/user_api.js
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user