"""用户可添加抖音账号数量限制。""" from __future__ import annotations from fastapi import HTTPException from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from models.models import Account, User from .roles import is_admin UNLIMITED_ACCOUNTS = -1 def normalize_max_accounts(value: int | None, role: str = "operator") -> int: if is_admin(role): return UNLIMITED_ACCOUNTS if value is None: return 3 try: parsed = int(value) except (TypeError, ValueError): return 3 if parsed < 0: return UNLIMITED_ACCOUNTS return parsed def account_limit_for_user(user: User) -> int | None: """返回 None 表示不限制。""" if is_admin(user.role): return None limit = user.max_accounts if user.max_accounts is not None else 3 if limit < 0: return None return limit async def count_user_accounts(db: AsyncSession, user_id: int) -> int: result = await db.execute( select(func.count()).select_from(Account).where(Account.owner_id == user_id) ) return int(result.scalar() or 0) async def count_user_account_breakdown(db: AsyncSession, user_id: int) -> dict[str, int]: """统计用户名下托管账号:总数 / 可用 / 额度停用。""" total = await count_user_accounts(db, user_id) if total <= 0: return {"total": 0, "active": 0, "disabled": 0} disabled_result = await db.execute( select(func.count()) .select_from(Account) .where(Account.owner_id == user_id, Account.quota_disabled.is_(True)) ) disabled = int(disabled_result.scalar() or 0) active = max(0, total - disabled) return {"total": total, "active": active, "disabled": disabled} async def ensure_can_add_account(db: AsyncSession, user: User) -> None: limit = account_limit_for_user(user) if limit is None: return count = await count_user_accounts(db, user.id) if count >= limit: raise HTTPException( status_code=400, detail=f"已达到可添加抖音账号上限({limit} 个),请购买额度或联系管理员", )