Restore Russian bot interface

This commit is contained in:
2026-07-20 08:58:10 +05:00
parent cea7da5d2b
commit 4adf9aa32e
7 changed files with 213 additions and 151 deletions
+129 -67
View File
@@ -49,32 +49,40 @@ def _user_card(uid: int) -> tuple[str, InlineKeyboardMarkup] | None:
if not profile:
return None
text = (
"<b>User</b>\n\n"
f"ID: <code>{uid}</code>\n"
f"Username: @{profile.username or '-'}\n"
f"Registered: {profile.registered or '-'}\n"
f"Balance: {profile.balance:.2f} RUB\n"
f"Total earned: {profile.total_earned:.2f} RUB\n"
f"Cookies: {profile.cookies_loaded}\n"
f"Referrals: {len(profile.referrals)}\n"
f"Admin: {'yes' if profile.is_admin else 'no'}\n"
f"Banned: {'yes: ' + profile.ban_reason if profile.is_banned else 'no'}"
"👤 <b>Пользователь</b>\n\n"
f"🆔 ID: <code>{uid}</code>\n"
f"👤 @{profile.username or ''}\n"
f"📅 Регистрация: {profile.registered or '?'}\n"
f"💳 Баланс: {profile.balance:.2f} \n"
f"💰 Всего заработано: {profile.total_earned:.2f} \n"
f"🍪 Cookie: {profile.cookies_loaded}\n"
f"👥 Рефералов: {len(profile.referrals)}\n"
f"👑 Админ: {'' if profile.is_admin else ''}\n"
f"🚫 Бан: {' ' + profile.ban_reason if profile.is_banned else ''}"
)
keyboard = InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(text="Add balance", callback_data=f"u_bal_add_{uid}"),
InlineKeyboardButton(text="Subtract balance", callback_data=f"u_bal_sub_{uid}"),
InlineKeyboardButton(
text=" Баланс", callback_data=f"u_bal_add_{uid}"
),
InlineKeyboardButton(
text=" Баланс", callback_data=f"u_bal_sub_{uid}"
),
],
[InlineKeyboardButton(
text="Unban" if profile.is_banned else "Ban",
callback_data=f"u_ban_{uid}",
)],
[InlineKeyboardButton(
text="Remove admin" if profile.is_admin else "Grant admin",
callback_data=f"u_admin_{uid}",
)],
[InlineKeyboardButton(text="Back", callback_data="admin_back")],
[
InlineKeyboardButton(
text="🚫 Разбанить" if profile.is_banned else "🚫 Забанить",
callback_data=f"u_ban_{uid}",
)
],
[
InlineKeyboardButton(
text="👑 Убрать админку" if profile.is_admin else "👑 Выдать админку",
callback_data=f"u_admin_{uid}",
)
],
[InlineKeyboardButton(text="🔙 Назад", callback_data="admin_back")],
]
)
return text, keyboard
@@ -85,7 +93,9 @@ async def cmd_admin(message: Message, state: FSMContext):
if not _admin(message.from_user.id):
return
await state.clear()
await message.answer("<b>Admin panel</b>", parse_mode="HTML", reply_markup=admin_menu_kb())
await message.answer(
"🛠 <b>Админ-панель</b>", parse_mode="HTML", reply_markup=admin_menu_kb()
)
@router.callback_query(F.data == "admin_close")
@@ -105,7 +115,7 @@ async def admin_back(callback: CallbackQuery, state: FSMContext):
if not _admin(callback.from_user.id):
return
await state.clear()
await safe_edit(callback, "<b>Admin panel</b>", reply_markup=admin_menu_kb())
await safe_edit(callback, "🛠 <b>Админ-панель</b>", reply_markup=admin_menu_kb())
await callback.answer()
@@ -115,7 +125,7 @@ async def admin_toggle_shop(callback: CallbackQuery):
return
enabled = toggle_shop()
await callback.message.edit_reply_markup(reply_markup=admin_menu_kb())
await callback.answer(f"Shop: {'ON' if enabled else 'OFF'}")
await callback.answer(f"Скупка: {'ВКЛ' if enabled else 'ВЫКЛ'}")
@router.callback_query(F.data == "admin_toggle_bot")
@@ -124,7 +134,7 @@ async def admin_toggle_bot(callback: CallbackQuery):
return
enabled = toggle_bot()
await callback.message.edit_reply_markup(reply_markup=admin_menu_kb())
await callback.answer(f"Bot: {'ON' if enabled else 'OFF'}")
await callback.answer(f"Бот: {'ВКЛ' if enabled else 'ВЫКЛ'}")
@router.callback_query(F.data == "admin_robsec_get")
@@ -133,18 +143,18 @@ async def admin_robsec_get(callback: CallbackQuery):
return
lines, size = robsec_info()
if not size:
await callback.answer("robsec.txt is empty", show_alert=True)
await callback.answer("robsec.txt пуст", show_alert=True)
return
try:
bot = get_bot() or callback.message.bot
await bot.send_document(
callback.from_user.id,
FSInputFile(ROBSEC_FILE),
caption=f"robsec.txt\nLines: {lines}\nSize: {size} bytes",
caption=f"📥 <b>robsec.txt</b>\nСтрок: <b>{lines}</b>\nРазмер: <b>{size} байт</b>",
)
await callback.answer("Sent")
await callback.answer("Отправлено")
except Exception as exc:
await callback.answer(f"Error: {exc}", show_alert=True)
await callback.answer(f"Ошибка: {exc}", show_alert=True)
@router.callback_query(F.data == "admin_robsec_clear")
@@ -154,11 +164,19 @@ async def admin_robsec_clear_prompt(callback: CallbackQuery):
lines, _ = robsec_info()
keyboard = InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text="Yes, clear", callback_data="admin_robsec_clear_yes")],
[InlineKeyboardButton(text="Cancel", callback_data="admin_back")],
[
InlineKeyboardButton(
text="✅ Да, очистить", callback_data="admin_robsec_clear_yes"
)
],
[InlineKeyboardButton(text="🔙 Отмена", callback_data="admin_back")],
]
)
await safe_edit(callback, f"Clear robsec.txt? Current lines: <b>{lines}</b>", reply_markup=keyboard)
await safe_edit(
callback,
f"🗑 <b>Очистить robsec.txt?</b>\n\nСтрок сейчас: <b>{lines}</b>\n\n⚠️ Данные будут удалены безвозвратно!",
reply_markup=keyboard,
)
@router.callback_query(F.data == "admin_robsec_clear_yes")
@@ -166,8 +184,8 @@ async def admin_robsec_clear_yes(callback: CallbackQuery):
if not _admin(callback.from_user.id):
return
clear_robsec()
await safe_edit(callback, "<b>robsec.txt cleared</b>", reply_markup=admin_menu_kb())
await callback.answer("Cleared")
await safe_edit(callback, "<b>robsec.txt очищен</b>", reply_markup=admin_menu_kb())
await callback.answer("Очищено")
@router.callback_query(F.data == "admin_rates")
@@ -176,13 +194,18 @@ async def admin_rates(callback: CallbackQuery):
return
cfg = load_config()
rows = [
[InlineKeyboardButton(text=f"{rate.name}: {rate.price:.2f} RUB", callback_data=f"admin_rate_{key}")]
[
InlineKeyboardButton(
text=f"{rate.name}: {rate.price:.2f}",
callback_data=f"admin_rate_{key}",
)
]
for key, rate in cfg.rates.items()
]
rows.append([InlineKeyboardButton(text="Back", callback_data="admin_back")])
rows.append([InlineKeyboardButton(text="🔙 Назад", callback_data="admin_back")])
await safe_edit(
callback,
"<b>Rate management</b>\nSelect a rate:",
"💰 <b>Управление курсами</b>\nВыберите курс для изменения цены:",
reply_markup=InlineKeyboardMarkup(inline_keyboard=rows),
)
await callback.answer()
@@ -196,13 +219,13 @@ async def admin_rate_select(callback: CallbackQuery, state: FSMContext):
cfg = load_config()
rate = cfg.rates.get(key)
if not rate:
await callback.answer("Rate not found", show_alert=True)
await callback.answer("Курс не найден", show_alert=True)
return
await state.update_data(rate_key=key)
await state.set_state(Form.admin_edit_rate)
await safe_edit(
callback,
f"Rate: <b>{rate.name}</b>\nCurrent price: {rate.price:.2f} RUB\n\nSend a new price:",
f"💰 Курс: <b>{rate.name}</b>\nТекущая цена: {rate.price:.2f} \n\nОтправьте новую цену числом:",
reply_markup=back_kb("admin_back"),
)
@@ -216,7 +239,7 @@ async def admin_edit_rate_save(message: Message, state: FSMContext):
if price < 0:
raise ValueError
except ValueError:
await message.answer("Send a non-negative number.")
await message.answer("❌ Введите неотрицательное число.")
return
data = await state.get_data()
key = data.get("rate_key")
@@ -226,7 +249,10 @@ async def admin_edit_rate_save(message: Message, state: FSMContext):
return
update_rate(key, price)
await state.clear()
await message.answer(f"Rate updated: {cfg.rates[key].name} = {price:.2f} RUB", reply_markup=admin_menu_kb())
await message.answer(
f"✅ Цена <b>{cfg.rates[key].name}</b> = {price:.2f}",
reply_markup=admin_menu_kb(),
)
@router.callback_query(F.data == "admin_min_withdraw")
@@ -236,7 +262,7 @@ async def admin_min_withdraw(callback: CallbackQuery, state: FSMContext):
await state.set_state(Form.admin_min_withdraw)
await safe_edit(
callback,
f"Current minimum withdrawal: {load_config().min_withdraw:.2f} RUB\nSend a new value:",
f"💳 Текущий минимальный вывод: {load_config().min_withdraw:.2f} \nОтправьте новое значение:",
reply_markup=back_kb("admin_back"),
)
@@ -250,11 +276,13 @@ async def admin_min_withdraw_save(message: Message, state: FSMContext):
if value <= 0:
raise ValueError
except ValueError:
await message.answer("Send a positive number.")
await message.answer("❌ Введите положительное число.")
return
update_min_withdraw(value)
await state.clear()
await message.answer(f"Minimum withdrawal updated to {value:.2f} RUB", reply_markup=admin_menu_kb())
await message.answer(
f"✅ Минимальный вывод: {value:.2f}", reply_markup=admin_menu_kb()
)
@router.callback_query(F.data == "admin_treasury")
@@ -262,7 +290,11 @@ async def admin_treasury(callback: CallbackQuery, state: FSMContext):
if not _admin(callback.from_user.id):
return
await state.set_state(Form.admin_treasury_amount)
await safe_edit(callback, "How much RUB should be added to the treasury?", reply_markup=back_kb("admin_back"))
await safe_edit(
callback,
"🏦 На какую сумму пополнить казну? (в ₽)\nОтправьте число:",
reply_markup=back_kb("admin_back"),
)
@router.message(Form.admin_treasury_amount)
@@ -274,22 +306,29 @@ async def admin_treasury_amount(message: Message, state: FSMContext):
if amount <= 0:
raise ValueError
except ValueError:
await message.answer("Send a positive number.")
await message.answer("❌ Введите положительное число.")
return
await state.clear()
invoice = await create_treasury_invoice(amount)
if not invoice:
await message.answer("CryptoBot invoice creation failed.", reply_markup=admin_menu_kb())
await message.answer(
"❌ Не удалось создать счет CryptoBot.", reply_markup=admin_menu_kb()
)
return
pay_url, invoice_id, amount_usdt = invoice
keyboard = InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text="Pay", url=pay_url)],
[InlineKeyboardButton(text="Check payment", callback_data=f"treasury_check_{invoice_id}_{amount}")],
[InlineKeyboardButton(text="💳 Оплатить", url=pay_url)],
[
InlineKeyboardButton(
text="✅ Проверить оплату",
callback_data=f"treasury_check_{invoice_id}_{amount}",
)
],
]
)
await message.answer(
f"Treasury invoice: <b>{amount:.2f} RUB</b> (~{amount_usdt} USDT)\nPay it and check the status.",
f"🏦 Счет на пополнение казны\n\n💰 Сумма: <b>{amount:.2f} </b> (~{amount_usdt} USDT)\n\nПосле оплаты нажмите «Проверить оплату».",
parse_mode="HTML",
reply_markup=keyboard,
)
@@ -307,11 +346,15 @@ async def treasury_check(callback: CallbackQuery):
paid = False
amount_rub = 0.0
if not paid:
await callback.answer("Payment has not arrived yet", show_alert=True)
await callback.answer("Оплата еще не поступила", show_alert=True)
return
balance = add_treasury(amount_rub)
await safe_edit(callback, f"Treasury topped up by {amount_rub:.2f} RUB. Total: {balance:.2f} RUB", reply_markup=admin_menu_kb())
await callback.answer("Paid")
await safe_edit(
callback,
f"✅ Казна пополнена на {amount_rub:.2f}\n🏦 Всего: {balance:.2f}",
reply_markup=admin_menu_kb(),
)
await callback.answer("Оплачено")
@router.callback_query(F.data == "admin_broadcast")
@@ -319,7 +362,11 @@ async def admin_broadcast_prompt(callback: CallbackQuery, state: FSMContext):
if not _admin(callback.from_user.id):
return
await state.set_state(Form.admin_broadcast)
await safe_edit(callback, "Send the broadcast text or a photo with caption.", reply_markup=back_kb("admin_back"))
await safe_edit(
callback,
"📣 Отправьте сообщение для рассылки (текст или фото с подписью):",
reply_markup=back_kb("admin_back"),
)
@router.message(Form.admin_broadcast)
@@ -333,7 +380,10 @@ async def admin_broadcast_send(message: Message, state: FSMContext):
photo_id=message.photo[-1].file_id if message.photo else None,
caption=message.caption,
)
await message.answer(f"Broadcast complete. Sent: {sent}, failed: {failed}.", reply_markup=admin_menu_kb())
await message.answer(
f"✅ Рассылка завершена. Отправлено: {sent}\n❌ Ошибок: {failed}",
reply_markup=admin_menu_kb(),
)
@router.callback_query(F.data == "admin_users")
@@ -341,7 +391,9 @@ async def admin_users(callback: CallbackQuery, state: FSMContext):
if not _admin(callback.from_user.id):
return
await state.set_state(Form.admin_find_user)
await safe_edit(callback, "Send a user ID or @username.", reply_markup=back_kb("admin_back"))
await safe_edit(
callback, "Отправьте ID пользователя или @username.", reply_markup=back_kb("admin_back")
)
@router.message(Form.admin_find_user)
@@ -351,7 +403,7 @@ async def admin_find_user(message: Message, state: FSMContext):
uid = find_user((message.text or "").strip())
await state.clear()
if uid is None:
await message.answer("User not found.", reply_markup=admin_menu_kb())
await message.answer("❌ Пользователь не найден.", reply_markup=admin_menu_kb())
return
card = _user_card(uid)
if card:
@@ -365,7 +417,9 @@ async def u_bal_add(callback: CallbackQuery, state: FSMContext):
uid = int(callback.data.removeprefix("u_bal_add_"))
await state.update_data(target_uid=uid)
await state.set_state(Form.admin_user_balance_add)
await safe_edit(callback, "Send the amount to add:", reply_markup=back_kb("admin_back"))
await safe_edit(
callback, "Отправьте сумму для начисления:", reply_markup=back_kb("admin_back")
)
@router.message(Form.admin_user_balance_add)
@@ -377,12 +431,14 @@ async def u_bal_add_save(message: Message, state: FSMContext):
if amount <= 0:
raise ValueError
except ValueError:
await message.answer("Send a positive number.")
await message.answer("❌ Введите положительное число.")
return
uid = (await state.get_data()).get("target_uid")
add_balance(uid, amount)
await state.clear()
await message.answer(f"Added {amount:.2f} RUB to {uid}.", reply_markup=admin_menu_kb())
await message.answer(
f"✅ Пользователю {uid} начислено {amount:.2f} ₽.", reply_markup=admin_menu_kb()
)
@router.callback_query(F.data.startswith("u_bal_sub_"))
@@ -392,7 +448,9 @@ async def u_bal_sub(callback: CallbackQuery, state: FSMContext):
uid = int(callback.data.removeprefix("u_bal_sub_"))
await state.update_data(target_uid=uid)
await state.set_state(Form.admin_user_balance_sub)
await safe_edit(callback, "Send the amount to subtract:", reply_markup=back_kb("admin_back"))
await safe_edit(
callback, "Отправьте сумму для списания:", reply_markup=back_kb("admin_back")
)
@router.message(Form.admin_user_balance_sub)
@@ -404,12 +462,14 @@ async def u_bal_sub_save(message: Message, state: FSMContext):
if amount <= 0:
raise ValueError
except ValueError:
await message.answer("Send a positive number.")
await message.answer("❌ Введите положительное число.")
return
uid = (await state.get_data()).get("target_uid")
sub_balance(uid, amount)
await state.clear()
await message.answer(f"Subtracted {amount:.2f} RUB from {uid}.", reply_markup=admin_menu_kb())
await message.answer(
f"У пользователя {uid} списано {amount:.2f} ₽.", reply_markup=admin_menu_kb()
)
@router.callback_query(F.data.startswith("u_ban_"))
@@ -424,11 +484,13 @@ async def u_ban(callback: CallbackQuery, state: FSMContext):
from services.admin import unban_user
unban_user(uid)
await callback.answer("Unbanned")
await callback.answer("Разблокирован")
else:
await state.update_data(target_uid=uid)
await state.set_state(Form.admin_user_ban_reason)
await safe_edit(callback, "Send the ban reason:", reply_markup=back_kb("admin_back"))
await safe_edit(
callback, "Отправьте причину блокировки:", reply_markup=back_kb("admin_back")
)
return
card = _user_card(uid)
if card:
@@ -440,7 +502,7 @@ async def u_ban_reason(message: Message, state: FSMContext):
if not _admin(message.from_user.id):
return
uid = (await state.get_data()).get("target_uid")
ban_user(uid, (message.text or "No reason").strip())
ban_user(uid, (message.text or "Причина не указана").strip())
await state.clear()
card = _user_card(uid)
if card:
@@ -453,7 +515,7 @@ async def u_admin(callback: CallbackQuery):
return
uid = int(callback.data.removeprefix("u_admin_"))
enabled = toggle_user_admin(uid)
await callback.answer(f"Admin: {'ON' if enabled else 'OFF'}")
await callback.answer(f"Админ: {'ВКЛ' if enabled else 'ВЫКЛ'}")
card = _user_card(uid)
if card:
await safe_edit(callback, card[0], reply_markup=card[1])