Archived
refactor: balance handling and upload processing
This commit is contained in:
+16
-16
@@ -18,14 +18,14 @@ class InsufficientBalance(BalanceError):
|
||||
|
||||
def _amount(value: int) -> int:
|
||||
if isinstance(value, bool) or not isinstance(value, int) or value <= 0:
|
||||
raise BalanceError("Amount must be a positive integer")
|
||||
raise BalanceError("Сумма должна быть положительным целым числом")
|
||||
return value
|
||||
|
||||
|
||||
async def _get_or_create_user(session, telegram_id: int) -> User:
|
||||
user = await session.scalar(select(User).where(User.telegram_id == telegram_id))
|
||||
if user is None:
|
||||
user = User(telegram_id=telegram_id, balance_credits=0)
|
||||
user = User(telegram_id=telegram_id, balance_rubles=0)
|
||||
session.add(user)
|
||||
await session.flush()
|
||||
return user
|
||||
@@ -34,7 +34,7 @@ async def _get_or_create_user(session, telegram_id: int) -> User:
|
||||
async def get_user_balance(telegram_id: int) -> int:
|
||||
async with async_session() as session:
|
||||
user = await session.scalar(select(User).where(User.telegram_id == telegram_id))
|
||||
return int(user.balance_credits) if user else 0
|
||||
return int(user.balance_rubles) if user else 0
|
||||
|
||||
|
||||
async def change_user_balance(
|
||||
@@ -46,26 +46,26 @@ async def change_user_balance(
|
||||
and telegram_id != actor_telegram_id
|
||||
and actor_telegram_id != ADMIN_ID
|
||||
):
|
||||
raise PermissionError("Only an administrator can adjust another user")
|
||||
raise PermissionError("Только администратор может изменять баланс другого пользователя")
|
||||
|
||||
async with async_session() as session:
|
||||
user = await _get_or_create_user(session, telegram_id)
|
||||
await session.execute(
|
||||
update(User).where(User.id == user.id).values(balance_credits=amount)
|
||||
update(User).where(User.id == user.id).values(balance_rubles=amount)
|
||||
)
|
||||
|
||||
await session.commit()
|
||||
return int(
|
||||
(
|
||||
await session.scalar(
|
||||
select(User.balance_credits).where(User.id == user.id)
|
||||
select(User.balance_rubles).where(User.id == user.id)
|
||||
)
|
||||
)
|
||||
or 0
|
||||
)
|
||||
|
||||
|
||||
async def credit_user(
|
||||
async def increase_balance(
|
||||
telegram_id: int, amount: int, *, actor_telegram_id: int | None = None
|
||||
) -> int:
|
||||
amount = _amount(amount)
|
||||
@@ -74,20 +74,20 @@ async def credit_user(
|
||||
and telegram_id != actor_telegram_id
|
||||
and actor_telegram_id != ADMIN_ID
|
||||
):
|
||||
raise PermissionError("Only an administrator can adjust another user")
|
||||
raise PermissionError("Только администратор может изменять баланс другого пользователя")
|
||||
|
||||
async with async_session() as session:
|
||||
user = await _get_or_create_user(session, telegram_id)
|
||||
await session.execute(
|
||||
update(User)
|
||||
.where(User.id == user.id)
|
||||
.values(balance_credits=User.balance_credits + amount)
|
||||
.values(balance_rubles=User.balance_rubles + amount)
|
||||
)
|
||||
await session.commit()
|
||||
return int(
|
||||
(
|
||||
await session.scalar(
|
||||
select(User.balance_credits).where(User.id == user.id)
|
||||
select(User.balance_rubles).where(User.id == user.id)
|
||||
)
|
||||
)
|
||||
or 0
|
||||
@@ -103,23 +103,23 @@ async def debit_user(
|
||||
and telegram_id != actor_telegram_id
|
||||
and actor_telegram_id != ADMIN_ID
|
||||
):
|
||||
raise PermissionError("Only an administrator can adjust another user")
|
||||
raise PermissionError("Только администратор может изменять баланс другого пользователя")
|
||||
|
||||
async with async_session() as session:
|
||||
user = await _get_or_create_user(session, telegram_id)
|
||||
result = await session.execute(
|
||||
update(User)
|
||||
.where(User.id == user.id, User.balance_credits >= amount)
|
||||
.values(balance_credits=User.balance_credits - amount)
|
||||
.where(User.id == user.id, User.balance_rubles >= amount)
|
||||
.values(balance_rubles=User.balance_rubles - amount)
|
||||
)
|
||||
if result.rowcount != 1:
|
||||
await session.rollback()
|
||||
raise InsufficientBalance("Insufficient balance")
|
||||
raise InsufficientBalance("Недостаточно рублей на балансе")
|
||||
await session.commit()
|
||||
return int(
|
||||
(
|
||||
await session.scalar(
|
||||
select(User.balance_credits).where(User.id == user.id)
|
||||
select(User.balance_rubles).where(User.id == user.id)
|
||||
)
|
||||
)
|
||||
or 0
|
||||
@@ -166,4 +166,4 @@ async def get_user_profile(telegram_id: int) -> tuple[int, int, int]:
|
||||
count = await session.scalar(
|
||||
select(func.count(BotAccount.id)).where(BotAccount.owner_id == user.id)
|
||||
)
|
||||
return telegram_id, int(user.balance_credits), int(count or 0)
|
||||
return telegram_id, int(user.balance_rubles), int(count or 0)
|
||||
|
||||
@@ -17,6 +17,25 @@ async def list_user_bot_accounts(telegram_id: int) -> list[BotAccount]:
|
||||
return list(result.scalars())
|
||||
|
||||
|
||||
async def list_user_activation_bot_accounts(telegram_id: int) -> list[BotAccount]:
|
||||
"""Возвращает личных ботов, доступных для активации ключей пользователем.
|
||||
|
||||
Боты, импортированные из ASF для совместимости с панелью администратора,
|
||||
являются системными, а не загруженными администратором лично.
|
||||
"""
|
||||
async with async_session() as session:
|
||||
result = await session.execute(
|
||||
select(BotAccount)
|
||||
.join(User)
|
||||
.where(
|
||||
User.telegram_id == telegram_id,
|
||||
BotAccount.source_filename != "existing-asf",
|
||||
)
|
||||
.order_by(BotAccount.bot_name)
|
||||
)
|
||||
return list(result.scalars())
|
||||
|
||||
|
||||
async def get_owned_bot(telegram_id: int, account_id: int) -> BotAccount | None:
|
||||
async with async_session() as session:
|
||||
result = await session.execute(
|
||||
@@ -67,7 +86,7 @@ async def user_hash_exists(telegram_id: int, config_sha256: str) -> bool:
|
||||
|
||||
|
||||
async def ensure_admin_compatibility(bot_names: list[str]) -> None:
|
||||
"""Keep ASF bots created before ownership was introduced visible to the admin."""
|
||||
"""Показывает администратору ботов ASF, созданных до добавления владельцев."""
|
||||
for bot_name in bot_names:
|
||||
if await bot_name_exists(bot_name):
|
||||
continue
|
||||
|
||||
+17
-3
@@ -111,12 +111,26 @@ async def redeem_single_bot_keys(bot_name: str, keys: list[str]) -> str:
|
||||
return text[:4000] + ("\n\n...обрезано" if len(text) > 4000 else "")
|
||||
|
||||
|
||||
async def redeem_all_bots_keys(keys: list[str], allowed_bots: list[str] | None = None) -> str:
|
||||
logger.info("Начата активация ключей по всем ботам: count=%s", len(keys))
|
||||
async def redeem_all_bots_keys(keys: list[str], allowed_bots: list[str]) -> str:
|
||||
"""Активирует ключи только на явно указанных личных ботах."""
|
||||
if not allowed_bots:
|
||||
logger.info("Нет личных ботов для массовой активации ключей")
|
||||
return (
|
||||
"Результат активации\n\n"
|
||||
"⚠️ У вас нет ботов, доступных для массовой активации.\n"
|
||||
"Ключи не отправлялись в ASF."
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Начата активация ключей на разрешенных ботах: keys=%s bots=%s",
|
||||
len(keys),
|
||||
len(allowed_bots),
|
||||
)
|
||||
response = get_all_bots()
|
||||
data = response.json()
|
||||
available = list(data.get("Result", {}).keys())
|
||||
bots = [name for name in available if allowed_bots is None or name in allowed_bots]
|
||||
allowed = set(allowed_bots)
|
||||
bots = [name for name in available if name in allowed]
|
||||
logger.info("Для массовой активации найдено ботов: count=%s", len(bots))
|
||||
success_count = 0
|
||||
failed_count = 0
|
||||
|
||||
Reference in New Issue
Block a user