This commit is contained in:
Yuriy Yuriev
2026-07-05 16:59:33 +07:00
parent f262616aad
commit 44ce29d2e0
9 changed files with 188 additions and 31 deletions
+114 -24
View File
@@ -69,6 +69,7 @@ class BotInterface:
self._topup_confirm: Dict[int, int] = {} # user_id -> rub amount pending confirm
self._user_task_state: Dict[int, dict] = {} # шаги создания задачи пользователем
self._admin_balance_state: Dict[int, int] = {} # admin_id -> target_user_id
self._admin_rub_state: Dict[int, int] = {} # admin_id -> target_user_id
self._admin_msg_state: Dict[int, int] = {} # admin_id -> target_user_id
self._menu_msg: Dict[int, int] = {} # user_id -> inline keyboard message_id
self._menu_top_msg: Dict[int, int] = {} # user_id -> reply keyboard message_id
@@ -1241,6 +1242,24 @@ class BotInterface:
pass
await callback.answer()
@dp.callback_query(F.data.startswith("ubal_menu_"))
async def cb_user_balance_menu(callback: CallbackQuery):
if not await require_admin(callback):
return
target_uid = int(callback.data.replace("ubal_menu_", "", 1))
builder = InlineKeyboardBuilder()
for amount in [10, 50, 100, 500]:
builder.button(text=f"+{amount}", callback_data=f"ubal_{amount}_{target_uid}")
builder.adjust(4)
builder.row(InlineKeyboardButton(text="✏️ Другая сумма", callback_data=f"ubal_custom_{target_uid}"))
builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data=f"udetail_{target_uid}"))
clicks = await interface.balance_storage.get_balance(target_uid)
await callback.message.edit_text(
f"👤 {target_uid} — переходов: {clicks}\n\nДобавить переходов:",
reply_markup=builder.as_markup()
)
await callback.answer()
@dp.callback_query(F.data.startswith("ubal_"))
async def cb_user_balance(callback: CallbackQuery):
if not await require_admin(callback):
@@ -1252,7 +1271,7 @@ class BotInterface:
interface._admin_balance_state[callback.from_user.id] = target_uid
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="❌ Отмена", callback_data=f"udetail_{target_uid}"))
await callback.message.answer("Введите сумму для пополнения:", reply_markup=builder.as_markup())
await callback.message.answer("Введите количество переходов:", reply_markup=builder.as_markup())
await callback.answer()
else:
amount = int(parts[1])
@@ -1261,6 +1280,44 @@ class BotInterface:
await callback.answer(f"✅ +{amount} переходов. Баланс: {new_balance}")
await interface._show_user_detail(callback, target_uid)
@dp.callback_query(F.data.startswith("urub_menu_"))
async def cb_user_rub_menu(callback: CallbackQuery):
if not await require_admin(callback):
return
target_uid = int(callback.data.replace("urub_menu_", "", 1))
builder = InlineKeyboardBuilder()
for amount in [100, 500, 1000, 3000]:
builder.button(text=f"+{amount}", callback_data=f"urub_{amount}_{target_uid}")
builder.adjust(4)
builder.row(InlineKeyboardButton(text="✏️ Другая сумма", callback_data=f"urub_custom_{target_uid}"))
builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data=f"udetail_{target_uid}"))
rub = await interface.rub_storage.get_balance(target_uid)
await callback.message.edit_text(
f"👤 {target_uid} — рублей: {rub}\n\nДобавить рублей:",
reply_markup=builder.as_markup()
)
await callback.answer()
@dp.callback_query(F.data.startswith("urub_"))
async def cb_user_rub(callback: CallbackQuery):
if not await require_admin(callback):
return
parts = callback.data.split("_")
# формат: urub_{amount}_{user_id} или urub_custom_{user_id}
if parts[1] == "custom":
target_uid = int(parts[2])
interface._admin_rub_state[callback.from_user.id] = target_uid
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text="❌ Отмена", callback_data=f"udetail_{target_uid}"))
await callback.message.answer("Введите сумму в рублях:", reply_markup=builder.as_markup())
await callback.answer()
else:
amount = int(parts[1])
target_uid = int(parts[2])
new_balance = await interface.rub_storage.add_balance(target_uid, amount)
await callback.answer(f"✅ +{amount} ₽. Баланс: {new_balance}")
await interface._show_user_detail(callback, target_uid)
@dp.callback_query(F.data.startswith("utasks_"))
async def cb_user_tasks_admin(callback: CallbackQuery):
if not await require_admin(callback):
@@ -1376,7 +1433,7 @@ class BotInterface:
await interface._show_user_menu(message)
return
# Ввод суммы баланса (admin)
# Ввод количества переходов (admin)
if user_id in interface._admin_balance_state:
target_uid = interface._admin_balance_state.pop(user_id)
await interface._safe_delete(message.bot, message.chat.id, message.message_id)
@@ -1385,7 +1442,21 @@ class BotInterface:
if amount <= 0:
raise ValueError
new_balance = await interface.balance_storage.add_balance(target_uid, amount)
await interface._send_temp(message, f"Пополнено на {amount}. Баланс: {new_balance}")
await interface._send_temp(message, f"+{amount} переходов. Баланс: {new_balance}")
except (ValueError, TypeError):
await interface._send_temp(message, "❌ Введите целое положительное число")
return
# Ввод рублёвого пополнения (admin)
if user_id in interface._admin_rub_state:
target_uid = interface._admin_rub_state.pop(user_id)
await interface._safe_delete(message.bot, message.chat.id, message.message_id)
try:
amount = int(text)
if amount <= 0:
raise ValueError
new_balance = await interface.rub_storage.add_balance(target_uid, amount)
await interface._send_temp(message, f"✅ +{amount} ₽. Баланс: {new_balance}")
except (ValueError, TypeError):
await interface._send_temp(message, "❌ Введите целое положительное число")
return
@@ -2389,7 +2460,7 @@ class BotInterface:
params.pending_visits += visits_count
params.total_planned_visits += visits_count
logger.info(f"🔗 @{username} {url}{visits_count} clicks ({calc_info}), total pending: {params.pending_visits}")
await send_message_safe(
notif_msg = await send_message_safe(
message.bot, message.chat.id,
f"🔗 @{username}: {url[:60]}\n"
f"📊 {calc_info}\n"
@@ -2402,6 +2473,7 @@ class BotInterface:
# Resume > 5 мин: серия этой ссылки полностью отбрасывается
SERIES_EXPIRY = 5 * 60
remaining = visits_count
successful_this_link = 0
paused_at: Optional[float] = None
first_click = True
@@ -2443,6 +2515,7 @@ class BotInterface:
return
if result.success:
params.successful_visits += 1
successful_this_link += 1
remaining -= 1
if params.user_id:
new_balance = await self.balance_storage.deduct(params.user_id, 1)
@@ -2470,6 +2543,15 @@ class BotInterface:
if params.stopped:
return
# Серия завершена — удаляем уведомление
if notif_msg:
try:
await message.bot.delete_message(
chat_id=message.chat.id,
message_id=notif_msg.message_id,
)
except Exception:
pass
except Exception as e:
logger.error(f"Process URL error: {e}")
@@ -3070,24 +3152,34 @@ class BotInterface:
await self._send_temp(message, "Ошибка запуска задачи")
async def _show_users_list(self, message: Message, edit: bool = False):
balances = await self.balance_storage.get_all()
all_tasks = await self.task_manager.get_all_tasks()
all_user_ids, all_tasks, all_clicks, all_rub = await asyncio.gather(
self.auth_storage.get_all_user_ids(),
self.task_manager.get_all_tasks(),
self.balance_storage.get_all(),
self.rub_storage.get_all(),
)
text = "👥 Пользователи\n\n"
text = f"👥 Пользователи ({len(all_user_ids)})\n\n"
builder = InlineKeyboardBuilder()
if not balances:
text += "Нет пользователей с балансом."
if not all_user_ids:
text += "Нет зарегистрированных пользователей."
else:
for uid_str, balance in list(balances.items())[:15]:
uid = int(uid_str)
for uid in all_user_ids[:20]:
clicks = all_clicks.get(str(uid), 0)
rub = all_rub.get(str(uid), 0)
active = sum(
1 for p in all_tasks.values()
if p.user_id == uid and not p.completed and not p.stopped
)
text += f"👤 `{uid}` — 💰 {balance} | 📋 {active} задач\n"
bal_str = f"🖱{clicks}"
if rub:
bal_str += f" 🪙{rub}"
if active:
bal_str += f" 📋{active}"
text += f"👤 `{uid}` — {bal_str}\n"
builder.row(InlineKeyboardButton(
text=f"👤 {uid} (💰{balance})",
text=f"👤 {uid} {bal_str}",
callback_data=f"udetail_{uid}",
))
@@ -3095,25 +3187,23 @@ class BotInterface:
await self._edit_or_send(message, text, builder.as_markup(), edit)
async def _show_user_detail(self, callback: CallbackQuery, target_user_id: int):
balance = await self.balance_storage.get_balance(target_user_id)
clicks = await self.balance_storage.get_balance(target_user_id)
rub = await self.rub_storage.get_balance(target_user_id)
all_tasks = await self.task_manager.get_all_tasks()
user_tasks = {tid: p for tid, p in all_tasks.items() if p.user_id == target_user_id}
active = sum(1 for p in user_tasks.values() if not p.completed and not p.stopped)
text = (
f"👤 Пользователь {target_user_id}\n\n"
f"🔢 Переходов: {balance}\n"
f"📋 Задач: {len(user_tasks)} (активных: {active})\n\n"
"Пополнить баланс:"
f"🖱 Переходов: {clicks}\n"
f"🪙 Рублей: {rub}\n"
f"📋 Задач: {len(user_tasks)} (активных: {active})\n"
)
builder = InlineKeyboardBuilder()
for amount in [10, 50, 100, 500]:
builder.button(text=f"+{amount}", callback_data=f"ubal_{amount}_{target_user_id}")
builder.adjust(4)
builder.row(InlineKeyboardButton(
text="✏️ Другая сумма",
callback_data=f"ubal_custom_{target_user_id}",
))
builder.row(InlineKeyboardButton(text=" Переходы", callback_data=f"ubal_menu_{target_user_id}"))
builder.row(InlineKeyboardButton(text=" Рубли", callback_data=f"urub_menu_{target_user_id}"))
if user_tasks:
builder.row(InlineKeyboardButton(
text=f"📋 Задачи ({len(user_tasks)})",