169 lines
5.7 KiB
Python
169 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
用户资料接口
|
|
功能:获取和更新用户资料
|
|
"""
|
|
|
|
from fastapi import APIRouter, HTTPException, Depends
|
|
from pydantic import BaseModel
|
|
from typing import Optional
|
|
from sqlalchemy.orm import Session
|
|
from app.db import get_db
|
|
from app.models.user import User
|
|
from app.models.business import PointsHistory
|
|
from app.core.security import get_current_user
|
|
|
|
router = APIRouter()
|
|
|
|
# ==================== 数据模型 ====================
|
|
|
|
class UserProfileUpdate(BaseModel):
|
|
nickname: Optional[str] = None
|
|
avatar: Optional[str] = None
|
|
email: Optional[str] = None
|
|
ai_provider: Optional[str] = None
|
|
ai_base_url: Optional[str] = None
|
|
ai_chat_base_url: Optional[str] = None
|
|
ai_vision_base_url: Optional[str] = None
|
|
ai_image_base_url: Optional[str] = None
|
|
ai_api_key: Optional[str] = None
|
|
ai_model: Optional[str] = None
|
|
ai_vision_model: Optional[str] = None
|
|
ai_image_model: Optional[str] = None
|
|
clear_ai_api_key: bool = False
|
|
|
|
|
|
def mask_api_key(value: Optional[str]) -> Optional[str]:
|
|
if not value:
|
|
return None
|
|
raw = value.strip()
|
|
if len(raw) <= 8:
|
|
return "*" * len(raw)
|
|
return f"{raw[:4]}{'*' * (len(raw) - 8)}{raw[-4:]}"
|
|
|
|
# ==================== 用户资料管理 ====================
|
|
|
|
@router.get("/user/profile")
|
|
async def get_user_profile(db: Session = Depends(get_db), current_username: str = Depends(get_current_user)):
|
|
"""获取用户资料"""
|
|
user = db.query(User).filter(User.username == current_username).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
|
|
user_data = {
|
|
"username": user.username,
|
|
"nickname": user.nickname,
|
|
"avatar": user.avatar,
|
|
"email": user.email,
|
|
"points": user.points,
|
|
"level": user.level,
|
|
"vip_type": user.vip_type,
|
|
"vip_expire": user.vip_expire.isoformat() if user.vip_expire else None,
|
|
"vip_daily_quota": user.vip_daily_quota,
|
|
"total_check_in_days": user.total_check_in_days,
|
|
"consecutive_check_in": user.consecutive_check_in,
|
|
"ai_provider": user.ai_provider or "ark",
|
|
"ai_base_url": user.ai_base_url or "",
|
|
"ai_chat_base_url": user.ai_chat_base_url or "",
|
|
"ai_vision_base_url": user.ai_vision_base_url or "",
|
|
"ai_image_base_url": user.ai_image_base_url or "",
|
|
"ai_model": user.ai_model or "",
|
|
"ai_vision_model": user.ai_vision_model or "",
|
|
"ai_image_model": user.ai_image_model or "",
|
|
"has_ai_api_key": bool(user.ai_api_key),
|
|
"ai_api_key_masked": mask_api_key(user.ai_api_key),
|
|
"created_at": user.created_at.isoformat() if user.created_at else None
|
|
}
|
|
|
|
return {
|
|
"code": 200,
|
|
"data": user_data
|
|
}
|
|
|
|
@router.put("/user/profile")
|
|
async def update_user_profile(data: UserProfileUpdate, db: Session = Depends(get_db), current_username: str = Depends(get_current_user)):
|
|
"""更新用户资料"""
|
|
user = db.query(User).filter(User.username == current_username).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
|
|
if data.nickname is not None:
|
|
user.nickname = data.nickname
|
|
if data.avatar is not None:
|
|
user.avatar = data.avatar
|
|
if data.email is not None:
|
|
user.email = data.email
|
|
if data.ai_provider is not None:
|
|
user.ai_provider = data.ai_provider.strip().lower() or None
|
|
if data.ai_base_url is not None:
|
|
user.ai_base_url = data.ai_base_url.strip() or None
|
|
if data.ai_chat_base_url is not None:
|
|
user.ai_chat_base_url = data.ai_chat_base_url.strip() or None
|
|
if data.ai_vision_base_url is not None:
|
|
user.ai_vision_base_url = data.ai_vision_base_url.strip() or None
|
|
if data.ai_image_base_url is not None:
|
|
user.ai_image_base_url = data.ai_image_base_url.strip() or None
|
|
if data.ai_model is not None:
|
|
user.ai_model = data.ai_model.strip() or None
|
|
if data.ai_vision_model is not None:
|
|
user.ai_vision_model = data.ai_vision_model.strip() or None
|
|
if data.ai_image_model is not None:
|
|
user.ai_image_model = data.ai_image_model.strip() or None
|
|
if data.clear_ai_api_key:
|
|
user.ai_api_key = None
|
|
elif data.ai_api_key is not None:
|
|
trimmed_key = data.ai_api_key.strip()
|
|
if trimmed_key:
|
|
user.ai_api_key = trimmed_key
|
|
|
|
db.commit()
|
|
|
|
return {
|
|
"code": 200,
|
|
"message": "更新成功"
|
|
}
|
|
|
|
# ==================== 积分历史 ====================
|
|
|
|
@router.get("/points/history")
|
|
async def get_points_history(
|
|
type: Optional[str] = None,
|
|
page: int = 1,
|
|
limit: int = 20,
|
|
db: Session = Depends(get_db),
|
|
current_username: str = Depends(get_current_user)
|
|
):
|
|
"""获取积分历史"""
|
|
user = db.query(User).filter(User.username == current_username).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
|
|
offset = (page - 1) * limit
|
|
|
|
query = db.query(PointsHistory).filter(PointsHistory.user_id == user.id)
|
|
|
|
if type:
|
|
query = query.filter(PointsHistory.type == type)
|
|
|
|
total = query.count()
|
|
records = query.order_by(PointsHistory.created_at.desc()).offset(offset).limit(limit).all()
|
|
|
|
result_records = []
|
|
for record in records:
|
|
result_records.append({
|
|
"type": record.type,
|
|
"amount": record.amount,
|
|
"balance": record.balance,
|
|
"description": record.description,
|
|
"created_at": record.created_at.isoformat() if record.created_at else None
|
|
})
|
|
|
|
return {
|
|
"code": 200,
|
|
"data": {
|
|
"total": total,
|
|
"current_balance": user.points,
|
|
"records": result_records
|
|
}
|
|
}
|