Files
kami_apple_exchage/backend/app/api/v1/user_data.py
danial 8bc8e1c664 feat(links): 实现基于权重的轮询算法和链接管理功能
- 新增链接权重字段,支持1-100范围设置
- 修改轮询算法为基于权重的选择机制
- 更新链接API接口返回统一使用LinkInfo模型
- 添加更新链接权重的PATCH端点
- 调整链接仓库查询逻辑,只包含激活状态链接
- 迁移链接相关Pydantic模型到task模块统一管理
- 修改分页响应格式为通用PaginatedResponse包装
- 禁用OpenTelemetry监控配置
2025-09-30 17:02:02 +08:00

234 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
用户数据相关的API接口
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_async_db
from app.core.log import get_logger
from app.schemas.user_data import (
UserDataCreate,
UserDataResponse,
UserDataUploadResponse,
)
from app.schemas.task import (
BulkDeleteUserDataResponse,
PaginatedResponse,
)
from app.services.user_data_service import UserDataService
logger = get_logger(__name__)
router = APIRouter()
def get_user_data_service(db: AsyncSession = Depends(get_async_db)) -> UserDataService:
"""获取用户数据服务实例"""
return UserDataService(db)
@router.post("/upload", response_model=UserDataUploadResponse, summary="上传用户数据")
async def upload_user_data(
user_data: UserDataCreate, service: UserDataService = Depends(get_user_data_service)
):
"""
上传用户数据并自动触发订单创建任务
- **first_name**: 名字(必填)
- **last_name**: 姓氏(必填)
- **email**: 邮箱(必填,唯一)
- **phone**: 电话(必填)
- **address**: 地址(必填)
- **city**: 城市(必填)
- **state**: 州/省(必填)
- **zip_code**: 邮编(必填)
- **country**: 国家(必填)
上传成功后,如果存在可用链接,系统会自动创建订单任务。
"""
try:
result = await service.upload_user_data(user_data)
logger.info(f"用户数据上传成功: email={user_data.email}")
return result
except ValueError as e:
logger.warning(
f"上传用户数据失败 - 参数验证错误: {str(e)}", email=user_data.email
)
raise HTTPException(status_code=400, detail=str(e))
@router.get(
"/detail/{user_id}", response_model=UserDataResponse, summary="获取用户数据详情"
)
async def get_user_data(
user_id: str, service: UserDataService = Depends(get_user_data_service)
):
"""
根据ID获取用户数据详情
- **user_id**: 用户数据ID
"""
try:
user_data = await service.get_user_data(user_id)
if not user_data:
logger.warning(f"获取用户数据详情失败 - 用户数据不存在: {user_id}")
raise HTTPException(status_code=404, detail="用户数据不存在")
logger.info(f"获取用户数据详情成功: {user_id}")
return user_data
except HTTPException:
raise
except Exception as e:
logger.error(f"获取用户数据详情失败: {str(e)}", user_id=user_id, exc_info=True)
raise HTTPException(status_code=500, detail="获取用户数据详情失败")
@router.delete("/all", response_model=BulkDeleteUserDataResponse, summary="批量删除所有用户数据")
async def bulk_delete_all_user_data(
skip_orders: bool = Query(False, description="是否跳过有关联订单的用户数据"),
service: UserDataService = Depends(get_user_data_service),
):
"""
批量软删除所有用户数据
- **skip_orders**: 是否跳过有关联订单的用户数据默认false会删除包括有关联订单的所有数据
返回删除统计信息,包括总用户数、删除用户数和跳过用户数
"""
try:
result = await service.delete_all_user_data(skip_orders=skip_orders)
logger.info(
f"批量删除用户数据完成: total={result['total_users']}, "
f"deleted={result['deleted_users']}, skipped={result['skipped_users']}"
)
return result
except Exception as e:
logger.error(f"批量删除用户数据失败: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail="批量删除用户数据失败")
@router.delete("/{user_id}", summary="删除用户数据")
async def delete_user_data(
user_id: str, service: UserDataService = Depends(get_user_data_service)
):
"""
删除用户数据
- **user_id**: 用户数据ID
注意:有关联订单的用户数据无法删除
"""
try:
success = await service.delete_user_data(user_id)
if not success:
logger.warning(f"删除用户数据失败 - 用户数据不存在: {user_id}")
raise HTTPException(status_code=404, detail="用户数据不存在")
logger.info(f"删除用户数据成功: {user_id}")
return {"message": "用户数据删除成功"}
except ValueError as e:
logger.warning(f"删除用户数据失败 - 参数验证错误: {str(e)}", user_id=user_id)
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"删除用户数据失败: {str(e)}", user_id=user_id, exc_info=True)
raise HTTPException(status_code=500, detail="删除用户数据失败")
@router.get("/list", response_model=PaginatedResponse[UserDataResponse], summary="获取用户数据列表")
async def get_user_data_list(
page: int = Query(1, ge=1, description="页码"),
size: int = Query(20, ge=1, le=100, description="每页大小"),
city: str | None = Query(None, description="城市过滤"),
state: str | None = Query(None, description="州/省过滤"),
country: str | None = Query(None, description="国家过滤"),
name_pattern: str | None = Query(None, description="姓名模糊搜索"),
service: UserDataService = Depends(get_user_data_service),
):
"""
获取用户数据列表,支持分页和过滤
- **page**: 页码从1开始
- **size**: 每页大小1-100
- **city**: 城市过滤
- **state**: 州/省过滤
- **country**: 国家过滤
- **name_pattern**: 姓名模糊搜索
"""
try:
result = await service.get_user_data_list(
page=page,
size=size,
city=city,
state=state,
country=country,
name_pattern=name_pattern,
)
return result
except Exception as e:
logger.error(f"获取用户数据列表失败: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail="获取用户数据列表失败")
@router.get("/task/{task_id}/status", summary="获取任务状态")
async def get_task_status(
task_id: str, service: UserDataService = Depends(get_user_data_service)
):
"""
获取订单创建任务的状态
- **task_id**: 任务ID从上传接口返回
"""
try:
result = await service.get_task_status(task_id)
logger.info(f"获取任务状态成功: task_id={task_id}")
return result
except Exception as e:
logger.error(f"获取任务状态失败: {str(e)}", task_id=task_id, exc_info=True)
raise HTTPException(status_code=500, detail="获取任务状态失败")
@router.post("/batch-upload", summary="批量上传用户数据")
async def batch_upload_user_data(
user_data_list: list[UserDataCreate],
service: UserDataService = Depends(get_user_data_service),
):
"""
批量上传用户数据
接受用户数据列表,批量创建并触发订单任务
"""
if len(user_data_list) > 100:
logger.warning(f"批量上传用户数据失败 - 超出最大限制: {len(user_data_list)}")
raise HTTPException(status_code=400, detail="批量上传最多支持100条数据")
try:
results = []
for user_data in user_data_list:
try:
result = await service.upload_user_data(user_data)
results.append(
{
"success": True,
"user_data": result.user_data,
"message": result.message,
}
)
except Exception as e:
results.append(
{"success": False, "error": str(e), "email": user_data.email}
)
success_count = sum(1 for r in results if r["success"])
logger.info(
f"批量上传用户数据完成: total={len(user_data_list)}, success={success_count}"
)
return {
"total": len(user_data_list),
"success": success_count,
"failed": len(user_data_list) - success_count,
"results": results,
}
except Exception as e:
logger.error(f"批量上传用户数据失败: {str(e)}", exc_info=True)
raise HTTPException(status_code=500, detail="批量上传用户数据失败")