- Profile API: GET/PUT /profile + PUT /profile/password - Messages API: 模型/迁移(005)/服务/路由 + 任务操作自动创建消息 - SSE 推送集成: tasks.py 中 6 个操作触发 SSE 通知 - Alembic 迁移: 004 audit_logs + 005 messages - env.py 导入所有模型确保迁移正确 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
174 lines
6.0 KiB
Python
174 lines
6.0 KiB
Python
"""
|
|
用户资料 API
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
|
|
from app.database import get_db
|
|
from app.models.user import User, UserRole
|
|
from app.models.organization import Brand, Agency, Creator
|
|
from app.api.deps import get_current_user
|
|
from app.services.auth import verify_password, hash_password
|
|
from app.schemas.profile import (
|
|
ProfileResponse,
|
|
ProfileUpdateRequest,
|
|
ChangePasswordRequest,
|
|
BrandProfile,
|
|
AgencyProfile,
|
|
CreatorProfile,
|
|
)
|
|
|
|
router = APIRouter(prefix="/profile", tags=["用户资料"])
|
|
|
|
|
|
def _build_profile_response(user: User, brand=None, agency=None, creator=None) -> ProfileResponse:
|
|
"""构建资料响应"""
|
|
resp = ProfileResponse(
|
|
id=user.id,
|
|
email=user.email,
|
|
phone=user.phone,
|
|
name=user.name,
|
|
avatar=user.avatar,
|
|
role=user.role.value,
|
|
is_verified=user.is_verified,
|
|
created_at=user.created_at,
|
|
)
|
|
if brand:
|
|
resp.brand = BrandProfile(
|
|
id=brand.id,
|
|
name=brand.name,
|
|
logo=brand.logo,
|
|
description=brand.description,
|
|
contact_name=brand.contact_name,
|
|
contact_phone=brand.contact_phone,
|
|
contact_email=brand.contact_email,
|
|
)
|
|
if agency:
|
|
resp.agency = AgencyProfile(
|
|
id=agency.id,
|
|
name=agency.name,
|
|
logo=agency.logo,
|
|
description=agency.description,
|
|
contact_name=agency.contact_name,
|
|
contact_phone=agency.contact_phone,
|
|
contact_email=agency.contact_email,
|
|
)
|
|
if creator:
|
|
resp.creator = CreatorProfile(
|
|
id=creator.id,
|
|
name=creator.name,
|
|
avatar=creator.avatar,
|
|
bio=creator.bio,
|
|
douyin_account=creator.douyin_account,
|
|
xiaohongshu_account=creator.xiaohongshu_account,
|
|
bilibili_account=creator.bilibili_account,
|
|
)
|
|
return resp
|
|
|
|
|
|
async def _get_role_entity(db: AsyncSession, user: User):
|
|
"""根据角色获取对应实体"""
|
|
if user.role == UserRole.BRAND:
|
|
result = await db.execute(select(Brand).where(Brand.user_id == user.id))
|
|
return result.scalar_one_or_none(), None, None
|
|
elif user.role == UserRole.AGENCY:
|
|
result = await db.execute(select(Agency).where(Agency.user_id == user.id))
|
|
return None, result.scalar_one_or_none(), None
|
|
elif user.role == UserRole.CREATOR:
|
|
result = await db.execute(select(Creator).where(Creator.user_id == user.id))
|
|
return None, None, result.scalar_one_or_none()
|
|
return None, None, None
|
|
|
|
|
|
@router.get("", response_model=ProfileResponse)
|
|
async def get_profile(
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取当前用户资料"""
|
|
brand, agency, creator = await _get_role_entity(db, current_user)
|
|
return _build_profile_response(current_user, brand, agency, creator)
|
|
|
|
|
|
@router.put("", response_model=ProfileResponse)
|
|
async def update_profile(
|
|
request: ProfileUpdateRequest,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""更新当前用户资料"""
|
|
# 更新 User 表通用字段
|
|
if request.name is not None:
|
|
current_user.name = request.name
|
|
if request.avatar is not None:
|
|
current_user.avatar = request.avatar
|
|
if request.phone is not None:
|
|
current_user.phone = request.phone
|
|
|
|
# 更新角色表字段
|
|
brand, agency, creator = await _get_role_entity(db, current_user)
|
|
|
|
if current_user.role == UserRole.BRAND and brand:
|
|
if request.name is not None:
|
|
brand.name = request.name
|
|
if request.description is not None:
|
|
brand.description = request.description
|
|
if request.contact_name is not None:
|
|
brand.contact_name = request.contact_name
|
|
if request.contact_phone is not None:
|
|
brand.contact_phone = request.contact_phone
|
|
if request.contact_email is not None:
|
|
brand.contact_email = request.contact_email
|
|
|
|
elif current_user.role == UserRole.AGENCY and agency:
|
|
if request.name is not None:
|
|
agency.name = request.name
|
|
if request.description is not None:
|
|
agency.description = request.description
|
|
if request.contact_name is not None:
|
|
agency.contact_name = request.contact_name
|
|
if request.contact_phone is not None:
|
|
agency.contact_phone = request.contact_phone
|
|
if request.contact_email is not None:
|
|
agency.contact_email = request.contact_email
|
|
|
|
elif current_user.role == UserRole.CREATOR and creator:
|
|
if request.name is not None:
|
|
creator.name = request.name
|
|
if request.avatar is not None:
|
|
creator.avatar = request.avatar
|
|
if request.bio is not None:
|
|
creator.bio = request.bio
|
|
if request.douyin_account is not None:
|
|
creator.douyin_account = request.douyin_account
|
|
if request.xiaohongshu_account is not None:
|
|
creator.xiaohongshu_account = request.xiaohongshu_account
|
|
if request.bilibili_account is not None:
|
|
creator.bilibili_account = request.bilibili_account
|
|
|
|
await db.commit()
|
|
|
|
# 重新查询返回最新数据
|
|
brand, agency, creator = await _get_role_entity(db, current_user)
|
|
return _build_profile_response(current_user, brand, agency, creator)
|
|
|
|
|
|
@router.put("/password")
|
|
async def change_password(
|
|
request: ChangePasswordRequest,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""修改密码"""
|
|
if not verify_password(request.old_password, current_user.password_hash):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="原密码不正确",
|
|
)
|
|
|
|
current_user.password_hash = hash_password(request.new_password)
|
|
await db.commit()
|
|
|
|
return {"message": "密码修改成功"}
|