feat(bot): add bot account ownership and balance

This commit is contained in:
2026-07-24 10:44:48 +05:00
parent 87385228ea
commit 8bd5c80693
22 changed files with 1008 additions and 393 deletions
+84 -183
View File
@@ -1,224 +1,125 @@
import random
import asyncio
from aiogram import Router
from aiogram.types import CallbackQuery
from bot.api.asf import get_all_bots
from bot.filters import AdminCallbackFilter
from bot.logging_utils import describe_user, get_logger
from bot.services.bots import is_bot_reloading, is_idle_enabled, update_idle_game
from bot.logging_utils import get_logger
from bot.services.bot_accounts import (
ensure_admin_compatibility,
get_owned_bot,
list_user_bot_accounts,
)
from bot.config import ADMIN_ID
from bot.services.twofa import stop_twofa_task
from bot.ui.formatters import format_bot_ui, get_farm_summary
from bot.ui.keyboards import bot_details_keyboard, bots_keyboard, games_keyboard
from bot.services.bots import is_bot_reloading, is_idle_enabled, update_idle_game
router = Router()
logger = get_logger(__name__)
@router.callback_query(lambda c: c.data == "bot_loading", AdminCallbackFilter())
async def owned_callback_bot(callback: CallbackQuery, prefix: str):
try:
account_id = int((callback.data or "").removeprefix(prefix))
except ValueError:
return None
return await get_owned_bot(callback.from_user.id, account_id)
@router.callback_query(lambda c: c.data == "bot_loading")
async def bot_loading_handler(callback: CallbackQuery) -> None:
logger.info(
"Пользователь %s нажал на еще не загруженного бота",
describe_user(callback.from_user),
)
await callback.answer(
"Аккаунт еще загружается. Попробуйте через несколько секунд.",
show_alert=True,
"Аккаунт ещё загружается. Попробуйте через несколько секунд.", show_alert=True
)
@router.callback_query(lambda c: c.data == "bots", AdminCallbackFilter())
@router.callback_query(lambda c: c.data == "bots")
async def bots_handler(callback: CallbackQuery) -> None:
logger.info(
"Пользователь %s открыл список ботов",
describe_user(callback.from_user),
)
await stop_twofa_task(callback.message.message_id)
response = get_all_bots()
await callback.answer()
try:
response = get_all_bots()
if response.status_code != 200:
logger.warning(
"Не удалось загрузить список ботов для %s: HTTP %s",
describe_user(callback.from_user),
response.status_code,
)
await callback.message.edit_text("Ошибка API")
return
data = response.json()
if not data.get("Success"):
logger.warning(
"ASF вернул неуспешный ответ при загрузке списка ботов для %s",
describe_user(callback.from_user),
)
await callback.message.edit_text("ASF вернул ошибку")
return
bots = data.get("Result", {})
logger.info(
"Список ботов для %s загружен: %s бот(ов)",
describe_user(callback.from_user),
len(bots),
)
text = f"<b>🤖 Ботов всего:</b> {len(bots)}\n\n{get_farm_summary(bots)}"
await callback.message.edit_text(text, reply_markup=bots_keyboard(bots))
except Exception as error:
logger.exception(
"Ошибка при открытии списка ботов для %s",
describe_user(callback.from_user),
)
await callback.message.edit_text(f"Ошибка: {error}")
@router.callback_query(
lambda c: c.data and c.data.startswith("bot_"), AdminCallbackFilter()
)
async def bot_selected(callback: CallbackQuery) -> None:
await stop_twofa_task(callback.message.message_id)
if not callback.data:
logger.debug(
"Колбэк выбора бота пришел без data от %s",
describe_user(callback.from_user),
)
await callback.answer()
if response.status_code != 200 or not response.json().get("Success"):
await callback.message.edit_text("Не удалось загрузить список ботов")
return
bot_name = callback.data.replace("bot_", "")
logger.info(
"Пользователь %s выбрал бота %s",
describe_user(callback.from_user),
bot_name,
)
if is_bot_reloading(bot_name):
logger.info(
"Бот %s перезагружается, карточка временно не отображается для %s",
bot_name,
describe_user(callback.from_user),
)
await callback.answer(
"Аккаунт перезагружается. Попробуйте через несколько секунд.",
show_alert=True,
)
return
asf_bots = response.json().get("Result", {})
if callback.from_user.id == ADMIN_ID:
await ensure_admin_compatibility(list(asf_bots))
try:
data = get_all_bots().json()
bots = data.get("Result", {})
bot = bots.get(bot_name)
if not bot or not bot.get("BotName") or not bot.get("SteamID"):
logger.info(
"Бот %s еще не готов к отображению для %s",
bot_name,
describe_user(callback.from_user),
)
await callback.answer(
"Аккаунт еще загружается. Попробуйте через несколько секунд.",
show_alert=True,
)
return
logger.info(
"Открыта карточка бота %s для %s",
bot_name,
describe_user(callback.from_user),
)
await callback.answer()
await callback.message.edit_text(
format_bot_ui(bot),
disable_web_page_preview=True,
reply_markup=bot_details_keyboard(
bot_name, bool(bot.get("HasMobileAuthenticator"))
),
)
except Exception as error:
logger.exception(
"Ошибка при открытии карточки бота %s для %s",
bot_name,
describe_user(callback.from_user),
)
await callback.message.edit_text(f"Ошибка: {error}")
@router.callback_query(
lambda c: c.data and c.data.startswith("games_"), AdminCallbackFilter()
)
async def games(callback: CallbackQuery) -> None:
await callback.answer()
if not callback.data:
logger.debug(
"Колбэк выбора игры пришел без data от %s",
describe_user(callback.from_user),
)
return
bot_name = callback.data.replace("games_", "")
idle_enabled = is_idle_enabled(bot_name, 730)
logger.info(
"Пользователь %s открыл меню накрутки часов для бота %s. CS2=%s",
describe_user(callback.from_user),
bot_name,
idle_enabled,
)
accounts = await list_user_bot_accounts(callback.from_user.id)
rows = [
(account.id, account.bot_name, asf_bots.get(account.bot_name, {}))
for account in accounts
]
await callback.message.edit_text(
"⌚ Выберите игру для накрутки часов",
reply_markup=games_keyboard(bot_name, idle_enabled),
f"<b>🤖 Ваших ботов:</b> {len(rows)}\n\n{get_farm_summary({name: bot for _, name, bot in rows})}",
reply_markup=bots_keyboard(rows),
)
@router.callback_query(
lambda c: c.data and c.data.startswith("farm|"), AdminCallbackFilter()
lambda c: c.data and c.data.startswith("bot_") and c.data != "bot_loading"
)
async def farm_game(callback: CallbackQuery) -> None:
async def bot_selected(callback: CallbackQuery) -> None:
account = await owned_callback_bot(callback, "bot_")
if account is None:
await callback.answer("Бот не найден или вам не принадлежит", show_alert=True)
return
await stop_twofa_task(callback.message.message_id)
if is_bot_reloading(account.bot_name):
await callback.answer(
"Аккаунт перезагружается. Попробуйте позже.", show_alert=True
)
return
bot = get_all_bots().json().get("Result", {}).get(account.bot_name)
if not bot or not bot.get("BotName") or not bot.get("SteamID"):
await callback.answer(
"Аккаунт ещё загружается. Попробуйте позже.", show_alert=True
)
return
await callback.answer()
if not callback.data:
logger.debug(
"Колбэк изменения фарма пришел без data от %s",
describe_user(callback.from_user),
)
return
_, bot_name, app_id_value = callback.data.split("|")
logger.info(
"Пользователь %s меняет игру для накрутки на боте %s: app_id=%s",
describe_user(callback.from_user),
bot_name,
app_id_value,
await callback.message.edit_text(
format_bot_ui(bot),
disable_web_page_preview=True,
reply_markup=bot_details_keyboard(
account.id, bool(bot.get("HasMobileAuthenticator"))
),
)
success, text, enabled = await update_idle_game(bot_name, int(app_id_value))
if not success:
logger.warning(
"Не удалось изменить игру для накрутки на боте %s для %s: %s",
bot_name,
describe_user(callback.from_user),
text,
)
await callback.answer(text, show_alert=True)
return
logger.info(
"Игра для накрутки на боте %s обновлена для %s. CS2=%s",
bot_name,
describe_user(callback.from_user),
enabled,
@router.callback_query(lambda c: c.data and c.data.startswith("games_"))
async def games(callback: CallbackQuery) -> None:
account = await owned_callback_bot(callback, "games_")
if account is None:
await callback.answer("Бот не найден или вам не принадлежит", show_alert=True)
return
await callback.answer()
enabled = is_idle_enabled(account.bot_name, 730)
await callback.message.edit_text(
"⌚ Выберите игру для накрутки часов",
reply_markup=games_keyboard(account.id, enabled),
)
await callback.answer(text, show_alert=True)
@router.callback_query(lambda c: c.data and c.data.startswith("farm|"))
async def farm_game(callback: CallbackQuery) -> None:
try:
_, account_id, app_id = (callback.data or "").split("|")
account = await get_owned_bot(callback.from_user.id, int(account_id))
app_id = int(app_id)
except (ValueError, TypeError):
account = None
if account is None:
await callback.answer("Бот не найден или вам не принадлежит", show_alert=True)
return
success, text, enabled = await update_idle_game(account.bot_name, app_id)
await callback.answer(text, show_alert=True)
if success:
await callback.message.edit_text(
text=f"⌚ Выберите игру для накрутки часов",
reply_markup=games_keyboard(bot_name, enabled),
)
except Exception:
logger.debug(
"Не удалось обновить клавиатуру игр для бота %s", bot_name, exc_info=True
"⌚ Выберите игру для накрутки часов",
reply_markup=games_keyboard(account.id, enabled),
)