71 lines
2.1 KiB
Python
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} 个),请购买额度或联系管理员",
|
|
)
|