Files
douyin/backend/auth/account_limits.py
2026-07-17 09:24:47 +08:00

71 lines
2.1 KiB
Python

"""用户可添加抖音账号数量限制。"""
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} 个),请购买额度或联系管理员",
)