· 6 months ago · Mar 19, 2025, 01:15 PM
1import random
2import os
3import string
4import logging
5import re
6from database import get_all_users # Импортируем функцию
7from database import execute_query # или другой модуль, где эта функция
8from aiogram import Bot, Dispatcher, types
9from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message, CallbackQuery
10from aiogram.dispatcher.filters import Command # Импорт Command
11from aiogram.utils import executor
12import time
13from aiogram.dispatcher.filters import Text
14from apscheduler.schedulers.asyncio import AsyncIOScheduler
15from aiogram.dispatcher.filters.state import StatesGroup, State
16from aiogram.dispatcher.filters.state import State, StatesGroup
17class BalanceInput(StatesGroup):
18 waiting_for_number_and_amount = State()
19from aiogram.dispatcher import FSMContext
20import sqlite3
21from datetime import datetime
22from datetime import timedelta
23from database import get_user_numbers
24from aiogram.types import ChatPermissions
25from collections import defaultdict
26from stats import user_stats, update_statistics # Импортируем из stats.py
27import pytz
28from aiogram.contrib.fsm_storage.memory import MemoryStorage
29import json
30
31logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
32
33# Функция для логирования user_stats и user_numbers
34def log_data(tag="DEBUG"):
35 logging.info(f"🟡 {tag} | user_numbers = {json.dumps(user_numbers, default=str, indent=2)}")
36 logging.info(f"🟡 {tag} | user_stats = {json.dumps(user_stats, default=str, indent=2)}")
37
38logging.basicConfig(level=logging.INFO)
39confirmed_numbers = []
40rejected_numbers = []
41# === 🔧 Настройки ===
42TOKEN = "" # Укажи свой токен
43ADMIN_GROUP_ID = -1002329021975 # ID группы админов
44REPORTS_CHAT_ID = -4795044900 # ID чата для отчётов (замени на нужный)
45ADMIN_USER_IDS = {8101813488, 987654321} # Выдача прав админа
46WITHDRAW_GROUP_ID = -1002290860098 # ID группы для заявок на вывод
47CHANNEL_USERNAME = "@legionWA_Rent" # ID вашего канала (например, "@your_channel")
48
49# Функция для подключения к базе данных
50def get_db_connection():
51 return sqlite3.connect("stats.db")
52
53# Создание таблицы, если её нет
54with get_db_connection() as conn:
55 cursor = conn.cursor()
56 cursor.execute('''CREATE TABLE IF NOT EXISTS stats (
57 user_id INTEGER PRIMARY KEY,
58 confirmed INTEGER DEFAULT 0,
59 skipped INTEGER DEFAULT 0,
60 dropped INTEGER DEFAULT 0,
61 errors INTEGER DEFAULT 0,
62 all_numbers INTEGER DEFAULT 0,
63 balance INTEGER DEFAULT 0,
64 daily_earnings INTEGER DEFAULT 0)''')
65 conn.commit()
66
67# Функция для получения статистики пользователя
68def get_user_stats(user_id):
69 with get_db_connection() as conn:
70 cursor = conn.cursor()
71 cursor.execute("SELECT * FROM stats WHERE user_id = ?", (user_id,))
72 stats = cursor.fetchone()
73 if not stats:
74 cursor.execute("INSERT INTO stats (user_id) VALUES (?)", (user_id,))
75 conn.commit()
76 return get_user_stats(user_id)
77 return stats
78
79# Функция обновления статистики
80def update_stat(user_id, column, value):
81 with get_db_connection() as conn:
82 cursor = conn.cursor()
83 cursor.execute(f"UPDATE stats SET {column} = {column} + ? WHERE user_id = ?", (value, user_id))
84 conn.commit()
85 logging.info(f"User {user_id}: {column} updated by {value}")
86
87# Структура для хранения статистики пользователей
88user_stats = defaultdict(lambda: {"hold": 0, "failed": 0, "skipped": 0, "added": 0})
89user_numbers = {}
90
91# Функция обновления статистики
92async def update_user_stats(user_id):
93 user_stats[user_id]['added'] += 1 # Увеличиваем количество добавленных номеров
94
95# Функция сброса статистики в 00:00 МСК
96async def reset_stats():
97 while True:
98 now = datetime.now()
99 moscow_time = now + timedelta(hours=3) # Перевод на МСК
100 reset_time = moscow_time.replace(hour=0, minute=0, second=0, microsecond=0)
101 sleep_time = (reset_time - moscow_time).total_seconds()
102 if sleep_time < 0:
103 sleep_time += 86400 # Перекатываем на следующий день
104 await asyncio.sleep(sleep_time)
105 user_stats.clear()
106 logging.info("Статистика сброшена")
107
108
109bot = Bot(token=TOKEN)
110storage = MemoryStorage() # Хранилище состояний
111dp = Dispatcher(bot, storage=storage) # Передаем storage в Dispatcher
112
113
114# Список пользователей и их балансов
115# Инициализация user_info как словаря для хранения информации о пользователе
116user_info = {}
117user_statistics = {}
118user_stats = {}
119user_balances = {} # Основной баланс
120user_bonus_balances = {} # Бонусный баланс
121user_numbers = {} # {номер: {"user_id": id, "msg_id": msg_id, "photo_sent": False, "confirmed": False}}
122
123# Словарь для хранения статистики пользователей
124user_stats = {}
125
126@dp.callback_query_handler(lambda c: c.data == "update_stats")
127async def refresh_stats(callback_query: types.CallbackQuery):
128 user_id = callback_query.from_user.id
129
130 # Проверяем, если статистика пользователя существует
131 if user_id not in user_stats:
132 await callback_query.answer("❌ Статистика не найдена.")
133 return
134
135 stats = user_stats[user_id]
136 stats_message = (
137 f"📊 Ваша статистика:\n"
138 f"🔹 Добавлено номеров: {stats['added']}\n"
139 f"🔹 В холде: {stats['hold']}\n"
140 f"🔹 Пропущено номеров: {stats['skipped']}\n"
141 f"🔹 Слетевших номеров: {stats['dropped']}\n"
142 f"🔹 Слеты: {stats['failed']}"
143 )
144
145 # Отправляем сообщение с обновленной статистикой
146 await callback_query.answer(stats_message)
147
148def get_user_stats(user_id: int):
149 """ Функция получения статистики пользователя, если её нет — создаем. """
150 if user_id not in user_stats:
151 user_stats[user_id] = {
152 "hold": 0, # В холде
153 "failed": 0, # Слеты
154 "skipped": 0, # Пропуски
155 "dropped": 0, # Слеты
156 "added": 0 # Добавлено
157 }
158 return user_stats[user_id]
159
160# Определение состояний
161class ReportForm(StatesGroup):
162 waiting_for_number = State() # Состояние для ввода номера
163
164# === 🎛 Классы для состояний ===
165class ReportForm(StatesGroup):
166 waiting_for_number = State()
167 waiting_for_time = State()
168
169# === Подключение к базе данных ===
170def get_user_numbers(user_id, status):
171 conn = sqlite3.connect("database.db")
172 cursor = conn.cursor()
173 cursor.execute("SELECT phone FROM user_numbers WHERE user_id=? AND status=?", (user_id, status))
174 numbers = cursor.fetchall()
175 conn.close()
176 return [num[0] for num in numbers]
177
178# === Проверка на администратора ===
179def is_admin(user_id):
180 return user_id in ADMIN_IDS
181
182#Словарь для хранения информации о подписке пользователей
183subscribed_users = {}
184
185# Проверка подписки на канал
186async def is_subscribed(user_id: int) -> bool:
187 try:
188 # Проверка, является ли пользователь подписчиком канала
189 member = await bot.get_chat_member(CHANNEL_ID, user_id)
190 # Если статус пользователя "member" или выше, то он подписан
191 return member.status in ['member', 'administrator', 'creator']
192 except Exception:
193 return False
194
195#Инициализация базы данных SQLite
196def init_db():
197 conn = sqlite3.connect("users.db")
198 cursor = conn.cursor()
199 cursor.execute('''CREATE TABLE IF NOT EXISTS users (
200 user_id INTEGER PRIMARY KEY,
201 username TEXT,
202 referral_code TEXT,
203 referred_by INTEGER,
204 balance REAL DEFAULT 0.0
205 )''')
206 conn.commit()
207 conn.close()
208
209#Функция для создания нового пользователя в базе данных
210def add_user(user_id, username, referral_code, referred_by=None):
211 conn = sqlite3.connect('users.db')
212 cursor = conn.cursor()
213 cursor.execute("""
214 CREATE TABLE IF NOT EXISTS users (
215 user_id INTEGER PRIMARY KEY,
216 username TEXT,
217 referral_code TEXT,
218 referred_by INTEGER,
219 balance REAL DEFAULT 0
220 )
221 """)
222 cursor.execute("INSERT INTO users (user_id, username, referral_code, referred_by) VALUES (?, ?, ?, ?)",
223 (user_id, username, referral_code, referred_by))
224 conn.commit()
225 conn.close()
226
227# Функция для получения информации о пользователе по ID
228def get_user(user_id):
229 conn = sqlite3.connect('users.db')
230 cursor = conn.cursor()
231 cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
232 user = cursor.fetchone()
233 conn.close()
234 return user
235
236# Функция для получения пользователя по реферальному коду
237def get_user_by_referral_code(referral_code):
238 conn = sqlite3.connect('users.db')
239 cursor = conn.cursor()
240 cursor.execute("SELECT * FROM users WHERE referral_code=?", (referral_code,))
241 user = cursor.fetchone()
242 conn.close()
243 return user
244
245# Функция для обновления баланса пользователя
246def update_balance(user_id, amount):
247 conn = sqlite3.connect('users.db')
248 cursor = conn.cursor()
249 cursor.execute("UPDATE users SET balance = balance + ? WHERE user_id=?", (amount, user_id))
250 conn.commit()
251 conn.close()
252
253# Генерация случайного реферального кода
254def generate_referral_code():
255 return ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
256
257def get_all_users():
258 conn = sqlite3.connect("bot_database.db")
259 cursor = conn.cursor()
260 cursor.execute("SELECT user_id FROM users")
261 users = [row[0] for row in cursor.fetchall()]
262 conn.close()
263 return users
264
265# Обновленный main_menu с кнопкой "Статистика"
266def main_menu():
267 menu = InlineKeyboardMarkup(row_width=2)
268 menu.add(
269 InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
270 InlineKeyboardButton("📊 Статистика", callback_data="stats_today")
271 )
272 menu.add(
273 InlineKeyboardButton("📋 Отчёт", callback_data="send_report"),
274 InlineKeyboardButton("💰 Баланс", callback_data="withdraw")
275 )
276 menu.add(
277 InlineKeyboardButton("📈 Реферальная система", callback_data="referral_system"),
278 InlineKeyboardButton("❓ FAQ", callback_data="faq")
279 )
280 return menu
281
282# === 📌 Обработчик команды /start ===
283@dp.message_handler(commands=['start'])
284async def start(message: types.Message):
285 user_id = message.from_user.id
286
287 if user_id not in subscribed_users or not subscribed_users[user_id]:
288 keyboard = InlineKeyboardMarkup()
289 keyboard.add(InlineKeyboardButton("🔗 Подписаться на канал", url="https://t.me/legionWA_Rent"))
290 keyboard.add(InlineKeyboardButton("🔄 Проверить подписку", callback_data="check_subscription"))
291
292 # Запрашиваем подписку перед тем, как показывать главное меню
293 await message.answer("Для того, чтобы продолжить, подпишитесь на наш канал:", reply_markup=keyboard)
294 subscribed_users[user_id] = False
295 else:
296 # Если подписка выполнена, показываем главное меню
297 await message.answer("🚀 Добро пожаловать! Выберите действие:", reply_markup=main_menu())
298
299@dp.message_handler(state=ReportForm.waiting_for_number)
300async def get_number(message: types.Message, state: FSMContext):
301 if not message.text.startswith("+7") or not message.text[1:].isdigit():
302 await message.answer("❌ Неверный формат номера! Введите в формате: `+7XXXXXXXXXX`", parse_mode="Markdown")
303 return
304
305 await state.update_data(number=message.text)
306 await message.answer("⏰ Теперь введите время связки (МСК) в формате `HH:MM`")
307 await ReportForm.waiting_for_time.set()
308
309@dp.message_handler(state=ReportForm.waiting_for_time)
310async def get_time(message: types.Message, state: FSMContext):
311 user_data = await state.get_data()
312 number = user_data["number"]
313 time = message.text.strip()
314
315 if not time.replace(":", "").isdigit() or len(time) not in [4, 5]:
316 await message.answer("❌ Неверный формат! Введите время в формате `HH:MM`")
317 return
318
319 report_text = f"📢 Новый отчёт!\n📞 Номер: {number}\n⏰ Время связки (МСК): {time}"
320 await bot.send_message(REPORTS_CHAT_ID, report_text)
321
322 await message.answer("✅ Отчёт отправлен администраторам!", reply_markup=main_menu())
323 await state.finish()
324
325# Обработчик команды /start с реферальной ссылкой
326@dp.message_handler(commands=['start'])
327async def start(message: types.Message):
328 referral_code = message.text.split()[-1] # Получаем реферальный код
329 user_id = message.from_user.id
330
331 # Проверяем, если пользователь перешел по реферальной ссылке
332 if referral_code:
333 referred_by_user = get_user_by_referral_code(referral_code)
334 if referred_by_user:
335 add_user(user_id, message.from_user.username, generate_referral_code(), referred_by=referred_by_user[0])
336 await message.answer(f"Вы зарегистрированы через реферальную ссылку @{referred_by_user[1]}.")
337 await message.answer("Добро пожаловать в систему!")
338
339 # Отчисляем 10% владельцу ссылки
340 referral_bonus = 10 # 10% от суммы, которую мы хотим начислить
341 update_balance(referred_by_user[0], referral_bonus)
342
343 # Отправляем владельцу ссылки информацию о новом пользователе
344 await bot.send_message(referred_by_user[0], f"Получено {referral_bonus} долларов за реферала @{message.from_user.username}!")
345
346 else:
347 await message.answer("❌ Неверная реферальная ссылка.")
348 else:
349 # Если реферальной ссылки нет, то просто генерируем новый код
350 referral_code = generate_referral_code()
351 add_user(user_id, message.from_user.username, referral_code)
352 await message.answer("Привет, добро пожаловать в наш бот! Используйте /referral для получения своей реферальной ссылки.")
353
354@dp.callback_query_handler(lambda c: c.data == "referral_system")
355async def referral_system(call: types.CallbackQuery):
356 user_id = call.from_user.id
357
358 # Получаем username бота
359 bot_username = (await bot.get_me()).username
360
361 if bot_username:
362 referral_link = f"https://t.me/{bot_username}?start={user_id}" # Генерируем ссылку для пользователя
363 else:
364 referral_link = "Ошибка: имя пользователя бота не настроено."
365
366 # Создаем клавиатуру с кнопкой "Назад"
367 keyboard = InlineKeyboardMarkup(row_width=1)
368 keyboard.add(
369 InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
370 )
371
372 # Редактируем текущее сообщение, а не отправляем новое
373 await call.message.edit_text(
374 f"Если вы пригласите своего друга, то будете получать с каждого его отстоявшего номера по 10%.\n\n"
375 f"Вот ваша реферальная ссылка: {referral_link}",
376 reply_markup=keyboard
377 )
378 await call.answer() # Закрываем индикатор загрузки
379
380@dp.callback_query_handler(lambda c: c.data == "stats_today")
381async def show_stats(callback_query: types.CallbackQuery):
382 user_id = callback_query.from_user.id
383 stats = user_stats.get(user_id, {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0})
384
385 # Логируем статистику перед формированием текста
386 logging.info(f"Показ статистики для пользователя {user_id}: {stats}")
387
388 # Формируем текст с актуальной статистикой
389 text = (
390 f"📊 *Ваша статистика:*\n"
391 f"├ В холде: {stats['hold']}\n"
392 f"├ Слетов: {stats['failed']}\n"
393 f"├ Пропущено: {stats['skipped']}\n"
394 f"├ Слетело: {stats['dropped']}\n"
395 f"└ Добавлено: {stats['added']}\n" # Добавлена строка для статистики по добавленным номерам
396 )
397
398 # Обновляем клавиатуру
399 keyboard = InlineKeyboardMarkup().add(
400 InlineKeyboardButton("🔄 Обновить статистику", callback_data="update_stats"),
401 InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
402 )
403
404 await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode="Markdown")
405 await callback_query.answer()
406
407# Обновление статистики вручную
408@dp.callback_query_handler(lambda c: c.data == "update_stats")
409async def refresh_stats(callback_query: types.CallbackQuery):
410 user_id = callback_query.from_user.id
411 # Получаем статистику пользователя
412 stats = user_stats.get(user_id, {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0}) # Добавлено "added"
413
414 # Формируем текст с актуальной статистикой
415 text = (
416 f"📊 *Ваша статистика:*\n"
417 f"├ В холде: {stats['hold']}\n"
418 f"├ Слетов: {stats['failed']}\n"
419 f"├ Пропущено: {stats['skipped']}\n"
420 f"├ Слетело: {stats['dropped']}\n"
421 f"└ Добавлено: {stats['added']}\n" # Добавлена строка для статистики по добавленным номерам
422 )
423
424 # Обновляем клавиатуру
425 keyboard = InlineKeyboardMarkup().add(
426 InlineKeyboardButton("🔄 Обновить статистику", callback_data="update_stats"),
427 InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
428 )
429
430 # Обновляем сообщение с актуальной статистикой
431 await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode="Markdown")
432 await callback_query.answer() # Подтверждаем обработку кнопки
433
434# === Обработчик проверки подписки ===
435@dp.callback_query_handler(lambda c: c.data == "check_subscription")
436async def check_subscription(call: types.CallbackQuery):
437 user_id = call.from_user.id
438
439 try:
440 chat_member = await bot.get_chat_member(CHANNEL_USERNAME, user_id)
441 if chat_member.status in ['member', 'administrator', 'creator']:
442 subscribed_users[user_id] = True
443 # Кнопка для начала работы
444 start_keyboard = InlineKeyboardMarkup().add(
445 InlineKeyboardButton("🚀 Начать работу", callback_data="start_work")
446 )
447 await call.message.answer("✅ Вы подписаны на канал. Теперь можно использовать все функции бота.", reply_markup=start_keyboard)
448 else:
449 await call.message.answer("❌ Вы не подписаны на канал. Пожалуйста, подпишитесь, чтобы продолжить.")
450 except Exception as e:
451 await call.message.answer(f"❌ Ошибка при проверке подписки: {e}")
452
453 await call.answer()
454
455# === 📌 Обработчик кнопки "Начать работу" ===
456@dp.callback_query_handler(lambda c: c.data == "start_work")
457async def start_work(callback_query: types.CallbackQuery):
458 # Действия, которые выполняются при нажатии на кнопку "Начать работу"
459
460 # Подтверждение действия
461 await callback_query.answer("👨💻 Вы начали работу!")
462
463 # Отправляем главное меню с кнопкой "Статистика"
464 await callback_query.message.edit_text("🚀 Добро пожаловать! Выберите действие:", reply_markup=main_menu())
465
466#=== 📤 Сдать номер ===
467# Обработчик нажатия кнопки "submit_number"
468@dp.callback_query_handler(lambda c: c.data == "submit_number")
469async def submit_number(call: types.CallbackQuery):
470 # Создаем клавиатуру с кнопкой "Назад"
471 keyboard = InlineKeyboardMarkup(row_width=1)
472 keyboard.add(
473 InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
474 )
475
476 # Редактируем текущее сообщение вместо отправки нового
477 await call.message.edit_text("📲 Введите номер в формате: `+7XXXXXXXXXX`", parse_mode="Markdown", reply_markup=keyboard)
478 await call.answer()
479
480# Обработчик на ввод номера
481@dp.message_handler(lambda message: message.text.startswith("+7"))
482async def receive_number(message: types.Message):
483 user_id = message.from_user.id
484 username = message.from_user.username or "Без имени"
485 number = message.text.strip()
486
487 logging.info(f"📌 Пользователь {user_id} ({username}) ввел номер: {number}")
488
489 # Проверка на уникальность номера
490 if number in user_numbers and user_numbers[number].get("confirmed"):
491 await message.answer("❌ Этот номер уже подтвержден.")
492 return
493
494 # Добавляем номер в user_numbers с флагом, что он еще не подтвержден
495 user_numbers[number] = {"user_id": user_id, "confirmed": False}
496
497 admin_message = f"📞 *Новый номер от @{username} (ID: `{user_id}`):*\n📲 `{number}`"
498
499 # Создание кнопок для администратора
500 keyboard = InlineKeyboardMarkup(row_width=2)
501 keyboard.add(
502 InlineKeyboardButton("Взять номер", callback_data=f"take_number_{number}"),
503 InlineKeyboardButton("Пропустить", callback_data=f"skip_number_{number}")
504 )
505
506 try:
507 # Отправляем сообщение в группу администраторов
508 msg = await bot.send_message(ADMIN_GROUP_ID, admin_message, parse_mode="Markdown", reply_markup=keyboard)
509 user_numbers[number]["msg_id"] = msg.message_id
510 logging.info(f"✅ Номер {number} отправлен в очередь для администратора.")
511 await message.answer("✅ Номер отправлен в очередь, ожидайте.")
512 except Exception as e:
513 await message.answer("❌ Ошибка отправки номера. Проверь настройки группы.")
514 logging.error(f"Ошибка отправки в группу: {e}")
515
516# Обработчик нажатия кнопки "Взять номер"
517@dp.callback_query_handler(lambda c: c.data.startswith("take_number_"))
518async def take_number(call: types.CallbackQuery):
519 number = call.data.split("_")[-1]
520 user_info = user_numbers.get(number)
521
522 if not user_info:
523 await call.answer("❌ Номер не найден.")
524 return
525
526 user_id = user_info["user_id"]
527
528 # Логируем информацию о пользователе
529 logging.info(f"Номер {number} найден для пользователя {user_id}. Обновляем его статус.")
530
531 # Обновляем статус номера на "added"
532 user_info["status"] = "added"
533 logging.info(f"Статус номера {number} изменён на 'added'.")
534
535 # Обновляем статистику пользователя для действия "added"
536 logging.info(f"Обновляем статистику для пользователя {user_id} с действием 'added'.")
537 update_statistics(user_id, "added")
538 logging.info(f"Статистика для пользователя {user_id} обновлена после добавления номера {number}.")
539
540 # Уведомляем пользователя о том, что номер добавлен
541 await bot.send_message(user_id, f"✅ Ваш номер {number} был добавлен в систему.")
542
543 # Логирование действия
544 logging.info(f"Номер {number} был добавлен для пользователя {user_id}.")
545
546 # Отправляем уведомление администратору
547 await bot.send_message(ADMIN_GROUP_ID, f"✅ Номер {number} был добавлен и принят в систему.")
548
549 # Удаляем сообщение с кнопками
550 await call.message.delete()
551
552 # Отвечаем на callback
553 await call.answer()
554
555# Обработчик для пропуска номера
556@dp.callback_query_handler(lambda c: c.data.startswith("skip_number_"))
557async def skip_number(call: types.CallbackQuery):
558 number = call.data.split("_")[-1]
559 user_info = user_numbers.get(number)
560
561 if not user_info:
562 await call.answer("❌ Номер не найден.")
563 return
564
565 # Удаляем сообщение с номером
566 await bot.delete_message(chat_id=ADMIN_GROUP_ID, message_id=user_info["msg_id"])
567
568 # Уведомляем администратора о пропуске
569 await bot.send_message(ADMIN_GROUP_ID, f"❌ Номер {number} был пропущен.")
570
571 # Отвечаем на callback
572 await call.answer()
573
574 # Удаляем номер из системы
575 del user_numbers[number]
576
577# Обработчик для получения номера от администратора
578@dp.message_handler(content_types=["photo"])
579async def admin_reply_photo(message: types.Message):
580 if not message.reply_to_message or message.chat.id != ADMIN_GROUP_ID:
581 return
582
583 text = message.reply_to_message.text or ""
584 number = re.search(r"\+7\d{10}", text)
585
586 if not number:
587 await message.reply("❌ Ошибка: номер не найден в сообщении.")
588 return
589
590 number = number.group(0)
591
592 if number not in user_numbers:
593 user_numbers[number] = {"user_id": message.from_user.id, "status": "pending"}
594
595 user_id = user_numbers[number]["user_id"]
596
597 keyboard = InlineKeyboardMarkup()
598 keyboard.add(
599 InlineKeyboardButton("✅ Код введен", callback_data=f"code_entered_{number}"),
600 InlineKeyboardButton("❌ Код не введен", callback_data=f"code_not_entered_{number}")
601 )
602
603 try:
604 photo = message.photo[-1].file_id
605 msg = await bot.send_photo(user_id, photo=photo, caption="🔑 Введите полученный код:", reply_markup=keyboard)
606
607 user_numbers[number]["msg_id"] = msg.message_id
608 user_numbers[number]["photo_sent"] = True
609
610 await message.reply("✅ Код отправлен пользователю.")
611 except Exception as e:
612 logging.exception(f"Ошибка отправки фото пользователю: {e}")
613 await message.reply("❌ Ошибка отправки фото пользователю.")
614
615# Функции для извлечения номера
616def normalize_number(number: str) -> str:
617 """Приводит номер к единому формату +7XXXXXXXXXX"""
618 number = number.replace(" ", "").strip()
619 if number.startswith("8"):
620 number = "+7" + number[1:]
621 return number
622
623def get_number_from_message(message: types.Message) -> str:
624 """Извлекает номер телефона из ответа администратора."""
625 if message.reply_to_message:
626 match = re.search(r"\+7\d{10}", message.reply_to_message.text or "")
627 return match.group(0) if match else None
628 return None
629
630@dp.callback_query_handler(lambda c: c.data == "send_report")
631async def send_report(call: types.CallbackQuery):
632 # Ссылка на чат для отчетов
633 report_chat_link = "https://t.me/report_legion" # Укажите правильную ссылку на ваш чат
634
635 # Создаем клавиатуру с кнопкой "Назад"
636 keyboard = InlineKeyboardMarkup(row_width=1)
637 keyboard.add(
638 InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
639 )
640
641 # Редактируем текущее сообщение, а не отправляем новое
642 await call.message.edit_text(
643 f"📌 Для отправки отчета, пожалуйста, перейдите в [чат для отчетов]({report_chat_link})",
644 parse_mode="Markdown",
645 reply_markup=keyboard
646 )
647
648 # Завершаем обработку callback
649 await call.answer()
650
651@dp.message_handler(commands=['get_chat_id'])
652async def get_chat_id(message: types.Message):
653 chat_id = message.chat.id
654 await message.answer(f"Chat ID: {chat_id}")
655
656@dp.message_handler(Command('ban'))
657async def ban_user(message: types.Message):
658 """Бан пользователя с указанием времени и причины."""
659
660 # Проверяем, является ли пользователь администратором
661 if message.chat.type != "private":
662 admins = await bot.get_chat_administrators(message.chat.id)
663 if message.from_user.id not in [admin.user.id for admin in admins]:
664 await message.answer("❌ Вы не являетесь администратором.")
665 return
666
667 # Разбираем команду, ожидаем формат: /ban @username 10m причина
668 parts = message.text.split(' ')
669 if len(parts) < 3:
670 await message.answer("❌ Неверный формат команды. Используйте: `/ban @username <время> <причина>`", parse_mode="Markdown")
671 return
672
673 username = parts[1] # @username
674 time_duration = parts[2] # Время (например, 10m, 1h, 1d)
675 reason = " ".join(parts[3:]) if len(parts) > 3 else "Не указана" # Причина (если указана)
676
677 # Проверка на правильность времени
678 try:
679 if time_duration[-1] == 'm': # минуты
680 ban_time = timedelta(minutes=int(time_duration[:-1]))
681 elif time_duration[-1] == 'h': # часы
682 ban_time = timedelta(hours=int(time_duration[:-1]))
683 elif time_duration[-1] == 'd': # дни
684 ban_time = timedelta(days=int(time_duration[:-1]))
685 else:
686 raise ValueError
687 except ValueError:
688 await message.answer("❌ Неверный формат времени. Используйте 'm' для минут, 'h' для часов, 'd' для дней.")
689 return
690
691 # Получаем ID пользователя по username
692 try:
693 user = await bot.get_chat_member(message.chat.id, username)
694 user_id = user.user.id
695 except Exception as e:
696 await message.answer(f"❌ Ошибка при получении информации о пользователе: {str(e)}")
697 return
698
699 # Дата окончания бана
700 ban_until = datetime.now(pytz.UTC) + ban_time
701
702 try:
703 # Баним пользователя на определенное время
704 await bot.ban_chat_member(chat_id=message.chat.id, user_id=user_id, until_date=ban_until)
705 await message.answer(f"✅ Пользователь {username} забанен на {time_duration}. Причина: {reason}")
706 except Exception as e:
707 await message.answer(f"❌ Не удалось забанить пользователя. Ошибка: {str(e)}")
708
709@dp.message_handler(Command('unban'))
710async def unban_user(message: types.Message):
711 """Разбан пользователя."""
712
713 # Проверяем, является ли пользователь администратором
714 if message.chat.type != "private":
715 admins = await bot.get_chat_administrators(message.chat.id)
716 if message.from_user.id not in [admin.user.id for admin in admins]:
717 await message.answer("❌ Вы не являетесь администратором.")
718 return
719
720 # Разбираем команду, ожидаем формат: /unban @username
721 parts = message.text.split(' ')
722 if len(parts) < 2:
723 await message.answer("❌ Неверный формат команды. Используйте: `/unban @username`", parse_mode="Markdown")
724 return
725
726 username = parts[1] # @username
727
728 # Получаем ID пользователя по username
729 try:
730 user = await bot.get_chat_member(message.chat.id, username)
731 user_id = user.user.id
732 except Exception as e:
733 await message.answer(f"❌ Ошибка при получении информации о пользователе: {str(e)}")
734 return
735
736 try:
737 # Разбаниваем пользователя
738 await bot.unban_chat_member(chat_id=message.chat.id, user_id=user_id, only_if_banned=True)
739 await message.answer(f"✅ Пользователь {username} был разбанен.")
740 except Exception as e:
741 await message.answer(f"❌ Не удалось разбанить пользователя. Ошибка: {str(e)}")
742
743#Обработка кнопки "Вернуться в меню"
744# Основное меню
745def main_menu():
746 menu = InlineKeyboardMarkup(row_width=2)
747
748 # Первый ряд: две кнопки
749 menu.add(
750 InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
751 InlineKeyboardButton("📋 Отчёт", callback_data="send_report")
752 )
753
754 # Второй ряд: две кнопки
755 menu.add(
756 InlineKeyboardButton("💰 Вывести", callback_data="withdraw"),
757 InlineKeyboardButton("📈 Реферальная система", callback_data="referral_system")
758 )
759
760 # Третий ряд: одна кнопка
761 menu.add(
762 InlineKeyboardButton("❓ FAQ", callback_data="faq")
763 )
764
765 return menu # Возвращаем сформированное меню
766
767# Отправляем главное меню
768async def main():
769 result = await some_coroutine()
770 print(result)
771
772@dp.callback_query_handler(lambda c: c.data.startswith("code_"))
773async def handle_code_confirmation(callback_query: types.CallbackQuery):
774 action, number = callback_query.data.split("_")[-2], callback_query.data.split("_")[-1]
775
776 logging.info(f"Кнопка нажата: {callback_query.data}")
777
778 if number not in user_numbers:
779 logging.error(f"❌ Ошибка: номер {number} не найден в системе.")
780 return await callback_query.answer("❌ Ошибка: номер не найден в системе.")
781
782 user_info = user_numbers[number]
783 user_id = user_info["user_id"]
784 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
785 user_info["confirmed_time"] = datetime.now()
786
787 # Обновляем статус номера в холд
788 if action == "entered":
789 # Здесь будет передача номера в холд
790 user_info["status"] = "hold" # Помечаем номер как "hold"
791 logging.info(f"Номер {number} добавлен в холд.")
792 elif action == "not_entered":
793 user_info["status"] = "rejected"
794
795 logging.info(f"Обновлен статус номера: {number} для пользователя: {user_id}, статус: {user_info['status']}")
796
797 # Обновляем статистику для пользователя
798 update_statistics(user_id, action) # Здесь обновляется статистика с действием, например "hold"
799
800 # Создаем клавиатуру с кнопкой "Назад"
801 back_button = InlineKeyboardMarkup().add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
802
803 # Отправляем соответствующие сообщения пользователю
804 if action == "entered":
805 await callback_query.answer("✅ Код подтвержден.")
806 await bot.send_message(user_info["user_id"], "✅ Ваш код был успешно подтвержден и теперь находится в холде.", reply_markup=back_button)
807 text = f"✅ Код подтвержден и добавлен в холд!\n📲 Номер: {number}\n⏰ Время: {timestamp}"
808
809 elif action == "not_entered":
810 await callback_query.answer("❌ Код не введен.")
811 await bot.send_message(user_info["user_id"], "❌ Ваш код не был подтвержден.", reply_markup=back_button)
812 text = f"❌ Код не введен!\n📲 Номер: {number}\n⏰ Время: {timestamp}"
813
814 # Кнопки для админов
815 skip_button = InlineKeyboardButton("⏭️ Пропустить номер", callback_data=f"skip_{number}")
816 drop_button = InlineKeyboardButton("⚠️ Слет", callback_data=f"drop_{number}")
817 action_keyboard = InlineKeyboardMarkup().add(skip_button, drop_button)
818
819 # Отправка сообщения в группу администраторов с кнопками
820 await bot.send_message(ADMIN_GROUP_ID, text, reply_markup=action_keyboard)
821
822 # Обновление кнопок для текущего сообщения
823 await callback_query.message.edit_reply_markup()
824
825# Функция для записи данных в таблицу (или базу данных)
826async def log_action_to_db(user_id: int, action: str, timestamp: str):
827 """Асинхронно записываем статистику в базу данных."""
828 db_data = {
829 "user_id": user_id,
830 "action": action,
831 "timestamp": timestamp,
832 "hold": user_stats[user_id]["hold"],
833 "failed": user_stats[user_id]["failed"],
834 "skipped": user_stats[user_id]["skipped"],
835 "dropped": user_stats[user_id]["dropped"],
836 "added": user_stats[user_id]["added"],
837 }
838 # Пример асинхронной записи в базу данных
839 await db.insert_user_data(db_data) # Замените на вашу асинхронную функцию
840 logging.info(f"Статистика для user_id={user_id} записана в БД: {db_data}")
841
842async def handle_code_entered(callback_query: types.CallbackQuery):
843 number = callback_query.data.split("_")[-1]
844 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Используйте datetime.now()
845
846 logging.info(f"📌 Код введен для номера: {number}")
847
848 # Проверяем, существует ли номер в системе
849 if number not in user_numbers:
850 logging.error(f"❌ Номер {number} не найден в системе.")
851 return await callback_query.answer("❌ Номер не найден в системе.")
852
853 # Получаем информацию о пользователе по номеру
854 user_info = user_numbers[number]
855 user_id = user_info["user_id"]
856
857 # Если пользователь еще не добавлен в статистику, создаем запись
858 if user_id not in user_stats:
859 logging.warning(f"⚠️ Статистика для пользователя {user_id} не найдена, создаём запись.")
860 user_stats[user_id] = {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0}
861
862 # Логируем информацию о пользователе
863 logging.info(f"Найден пользователь: {user_id}, статус: {user_info['status']}")
864
865 # Обновляем статус номера на "hold"
866 user_info["status"] = "hold"
867 logging.info(f"✅ Обновлено: user_id={user_id}, статус={user_info['status']}")
868
869 # Обновляем статистику с действием 'hold' (в холде)
870 update_statistics(user_id, "hold") # Добавляем статистику для действия "hold"
871 logging.info(f"Номер {number} добавлен в холд для пользователя {user_id}. Статистика обновлена.")
872
873 # Запись статистики в базу данных после обновления
874 log_action_to_db(user_id, "hold", timestamp) # Записываем в базу
875
876 # Отправляем сообщение пользователю и администратору
877 await bot.send_message(user_id, f"✅ Ваш номер в обработке.\n📞 Номер: {number}\n⏰ Время: {timestamp}")
878 await bot.send_message("ADMIN_GROUP_ID", f"✅ Номер {number} добавлен в холд.\n⏰ Время: {timestamp}")
879
880 # Отвечаем на запрос callback
881 await callback_query.answer("✅ Код подтвержден, номер добавлен в холд.")
882 await callback_query.message.edit_reply_markup()
883
884@dp.callback_query_handler(lambda c: c.data.startswith("drop_"))
885async def handle_drop(callback_query: types.CallbackQuery):
886 number = callback_query.data.split("_")[-1]
887 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
888
889 log_data("BEFORE DROP") # 🔥 Логируем перед выполнением
890
891 # Проверяем, есть ли номер в системе
892 if number not in user_numbers:
893 return await callback_query.answer("❌ Номер не найден в системе.")
894
895 # Получаем user_id и информацию о номере
896 user_info = user_numbers[number]
897 user_id = user_info["user_id"]
898
899 # 🔥 Исправление: Если user_stats[user_id] не существует — создаем!
900 if user_id not in user_stats:
901 logging.warning(f"⚠️ Пользователь {user_id} отсутствует в user_stats! Создаю запись...")
902 user_stats[user_id] = {
903 "hold": 0,
904 "failed": 0,
905 "skipped": 0,
906 "dropped": 0,
907 }
908
909 # 🔍 Проверяем, был ли номер в холде
910 if user_info.get("status") != "hold":
911 logging.warning(f"⚠️ Попытка удалить номер {number}, но он не был в холде!")
912 return await callback_query.answer("❌ Ошибка: этот номер не был в холде!")
913
914 # Уменьшаем счётчик "В холде" и увеличиваем "Слеты"
915 if user_stats[user_id]["hold"] > 0:
916 user_stats[user_id]["hold"] -= 1
917 user_stats[user_id]["dropped"] += 1
918
919 # Обновляем статус номера
920 user_numbers[number]["status"] = "dropped"
921
922 log_data("AFTER DROP") # 🔥 Логируем после выполнения
923
924 # Отправляем уведомления
925 await bot.send_message(user_id, f"⚠️ Ваш номер слетел.\n📞 Номер: {number}\n⏰ Время: {timestamp}")
926 await bot.send_message(ADMIN_GROUP_ID, f"⚠️ Номер {number} слетел!\n⏰ Время: {timestamp}")
927
928 await callback_query.answer("✅ Слет зафиксирован, статистика обновлена.")
929 await callback_query.message.edit_reply_markup()
930
931@dp.callback_query_handler(lambda c: c.data == "back_to_main_menu")
932async def back_to_main_menu(call: types.CallbackQuery):
933 # Создаем клавиатуру с двумя столбцами
934 keyboard = InlineKeyboardMarkup(row_width=2) # Устанавливаем 2 кнопки в строке
935
936 # Добавляем кнопки
937 keyboard.add(
938 InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
939 InlineKeyboardButton("📊 Статистика", callback_data="stats_today"),
940 InlineKeyboardButton("🎁 Реферальная система", callback_data="referral_system"),
941 InlineKeyboardButton("📌 Отправить отчет", callback_data="send_report"),
942 InlineKeyboardButton("💰 Баланс", callback_data="withdraw"),
943 InlineKeyboardButton("❓ FAQ", callback_data="faq")
944 )
945
946 # Отправляем сообщение с клавиатурой
947 await call.message.edit_text("🏠 Главное меню:", reply_markup=keyboard)
948 await call.answer()
949
950logging.info(f"📊 user_numbers ДО обработки: {user_numbers}")
951logging.info(f"📊 user_stats ДО обработки: {user_stats}")
952
953# Функция обновления статистики
954async def update_user_stats(user_id):
955 user_stats[user_id]['hold'] += 1 # Увеличиваем количество номеров в холде
956
957# Обработчик кнопки "Код введен"
958@dp.callback_query_handler(lambda c: c.data.startswith("code_entered_"))
959async def handle_code_entered(callback_query: types.CallbackQuery):
960 user_id = callback_query.from_user.id
961 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
962 update_stat(user_id, "confirmed", 1)
963 log_action_to_db(user_id, "code_entered", timestamp)
964 await bot.send_message(user_id, f"✅ Ваш номер в обработке.\n⏰ Время: {timestamp}")
965 await bot.send_message("ADMIN_GROUP_ID", f"✅ Номер добавлен в Подтвержденные.\n⏰ Время: {timestamp}")
966 await callback_query.answer("✅ Код подтвержден, номер добавлен в Подтвержденные")
967 await callback_query.message.edit_reply_markup()
968
969#=== 💰 Вывести средства ===
970@dp.callback_query_handler(lambda c: c.data == "withdraw")
971async def withdraw_request(call: types.CallbackQuery):
972 user_id = call.from_user.id
973 balance = user_balances.get(user_id, 0) # Основной баланс
974 bonus_balance = user_bonus_balances.get(user_id, 0) # Бонусный баланс
975
976 if balance <= 0 and bonus_balance <= 0:
977 await call.message.edit_text("❌ У вас нет средств на вывод.", reply_markup=InlineKeyboardMarkup().add(
978 InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
979 ))
980 await call.answer()
981 return
982
983 # Создаем клавиатуру с кнопками вывода
984 keyboard = InlineKeyboardMarkup(row_width=1)
985 if balance > 0:
986 keyboard.add(InlineKeyboardButton("💸 Вывести с основного баланса", callback_data="withdraw_main"))
987 if bonus_balance > 0:
988 keyboard.add(InlineKeyboardButton("🎁 Вывести с бонусного баланса", callback_data="withdraw_bonus"))
989 keyboard.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
990
991 # Отображаем балансы и клавиатуру
992 await call.message.edit_text(
993 f"💰 *Ваш баланс:*\n"
994 f"💵 Основной баланс: {balance} USD\n"
995 f"🎁 Бонусный баланс: {bonus_balance} USD",
996 parse_mode="Markdown",
997 reply_markup=keyboard
998 )
999 await call.answer()
1000
1001# Обработчик выбора вывода с основного баланса
1002@dp.callback_query_handler(lambda c: c.data == "withdraw_main")
1003async def withdraw_main(call: types.CallbackQuery):
1004 await start_withdraw(call, "main")
1005
1006# Обработчик выбора вывода с бонусного баланса
1007@dp.callback_query_handler(lambda c: c.data == "withdraw_bonus")
1008async def withdraw_bonus(call: types.CallbackQuery):
1009 await start_withdraw(call, "bonus")
1010
1011# Универсальный обработчик начала вывода
1012async def start_withdraw(call: types.CallbackQuery, balance_type: str):
1013 user_id = call.from_user.id
1014 balance = user_balances.get(user_id, 0) if balance_type == "main" else user_bonus_balances.get(user_id, 0)
1015
1016 if balance <= 0:
1017 await call.message.edit_text("❌ Недостаточно средств для вывода.", reply_markup=InlineKeyboardMarkup().add(
1018 InlineKeyboardButton("⬅️ Назад", callback_data="withdraw")
1019 ))
1020 await call.answer()
1021 return
1022
1023 keyboard = InlineKeyboardMarkup().add(
1024 InlineKeyboardButton("❌ Отменить", callback_data="withdraw")
1025 )
1026
1027 await call.message.edit_text(
1028 f"💰 Введите сумму для вывода в долларах ({'основной' if balance_type == 'main' else 'бонусный'} баланс):",
1029 reply_markup=keyboard
1030 )
1031 await call.answer()
1032
1033 # Сохраняем тип баланса, чтобы знать, откуда списывать средства
1034 user_withdraw_requests[user_id] = balance_type
1035
1036# Обработчик ввода суммы для вывода
1037user_withdraw_requests = {} # Временное хранилище запросов вывода
1038
1039@dp.message_handler(lambda message: message.text.replace('.', '', 1).isdigit())
1040async def handle_withdraw_amount(message: types.Message):
1041 user_id = message.from_user.id
1042 amount = float(message.text)
1043
1044 # Определяем, с какого баланса идет вывод
1045 balance_type = user_withdraw_requests.get(user_id)
1046 if not balance_type:
1047 await message.answer("❌ Ошибка: неизвестный источник вывода.")
1048 return
1049
1050 balance = user_balances.get(user_id, 0) if balance_type == "main" else user_bonus_balances.get(user_id, 0)
1051
1052 if amount > balance:
1053 await message.answer("❌ У вас недостаточно средств для вывода.")
1054 return
1055
1056 if amount <= 0:
1057 await message.answer("❌ Сумма вывода должна быть положительной.")
1058 return
1059
1060 # Обновляем баланс пользователя
1061 if balance_type == "main":
1062 user_balances[user_id] -= amount
1063 else:
1064 user_bonus_balances[user_id] -= amount
1065
1066 # Отправляем заявку на вывод в группу администраторов
1067 await bot.send_message(
1068 WITHDRAW_GROUP_ID,
1069 f"💰 @{message.from_user.username} (ID: {user_id}) хочет вывести {amount} USD с {'основного' if balance_type == 'main' else 'бонусного'} баланса."
1070 )
1071
1072 keyboard = InlineKeyboardMarkup().add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
1073 await message.answer(f"✅ Запрос на вывод {amount} USD отправлен на проверку.", reply_markup=keyboard)
1074
1075 # Удаляем временные данные
1076 user_withdraw_requests.pop(user_id, None)
1077
1078# === ❓ FAQ ===
1079@dp.callback_query_handler(lambda c: c.data == "faq")
1080async def faq(call: types.CallbackQuery):
1081 faq_text = """**❓ FAQ ❓**
10821️⃣ Мы не несем ответственность за аккаунты.
10832️⃣ В случае скама офиса, выплаты не гарантируются.
10843️⃣ Если номер отстоял 59 мин вместо 1 часа — оплаты не будет.
10854️⃣ Выплаты в течение 7 дней.
10865️⃣ Постоянный «Скип» может привести к блокировке.
10876️⃣ Принимаются только РФ номера 6+ месяцев.
10887️⃣ Администрация имеет право исключить вас без объяснений."""
1089
1090 # Создаем инлайн кнопку "⬅️ Назад"
1091 keyboard = InlineKeyboardMarkup()
1092 keyboard.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
1093
1094 # Редактируем текущее сообщение вместо отправки нового
1095 await call.message.edit_text(faq_text, parse_mode="Markdown", reply_markup=keyboard)
1096 await call.answer()
1097
1098@dp.message_handler(commands=["broadcast"])
1099async def start_broadcast(message: types.Message):
1100 if message.from_user.id not in ADMIN_USER_IDS:
1101 return await message.answer("❌ У вас нет прав для рассылки.")
1102
1103 await message.answer("Введите текст для рассылки:")
1104 await dp.current_state(user=message.from_user.id).set_state("waiting_for_broadcast")
1105
1106@dp.message_handler(state="waiting_for_broadcast")
1107async def send_broadcast(message: types.Message, state):
1108 text = message.text
1109 users = get_all_users()
1110
1111 sent_count = 0
1112 failed_count = 0
1113
1114 for user_id in users:
1115 try:
1116 await bot.send_message(user_id, text)
1117 sent_count += 1
1118 await asyncio.sleep(0.5) # Антиспам-задержка
1119 except Exception:
1120 failed_count += 1
1121
1122 await message.answer(f"✅ Рассылка завершена! Отправлено: {sent_count}, Ошибок: {failed_count}.")
1123 await state.finish()
1124
1125# Убедитесь, что эта функция не принимает никаких аргументов
1126def admin_panel():
1127 menu = InlineKeyboardMarkup(row_width=2)
1128 menu.add(
1129 InlineKeyboardButton("📊 Общая статистика", callback_data="admin_stats"),
1130 InlineKeyboardButton("📜 Список", callback_data="admin_list"), # список
1131 #InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
1132 #InlineKeyboardButton("💰 Вывести", callback_data="withdraw")
1133 )
1134 return menu
1135
1136 #Функция для получения ТОЛЬКО подтвержденных номеров
1137def get_confirmed_numbers():
1138 connection = sqlite3.connect('your_database.db')
1139 cursor = connection.cursor()
1140
1141 try:
1142 cursor.execute("SELECT number, time FROM confirmed_numbers")
1143 confirmed_numbers = cursor.fetchall()
1144
1145 logging.info(f"📂 Данные из базы: {confirmed_numbers}") # Логируем, что возвращает БД
1146
1147 return confirmed_numbers
1148 except Exception as e:
1149 logging.error(f"❌ Ошибка при запросе данных: {e}")
1150 return []
1151 finally:
1152 connection.close()
1153
1154conn = sqlite3.connect("bot_database.db")
1155cursor = conn.cursor()
1156
1157cursor.execute("SELECT * FROM confirmed_numbers")
1158numbers = cursor.fetchall()
1159
1160if numbers:
1161 print("✅ Подтвержденные номера:", numbers)
1162else:
1163 print("⚠️ В таблице confirmed_numbers нет данных!")
1164
1165conn.close()
1166
1167# Функция для создания таблицы, если ее еще нет
1168def create_table():
1169 connection = sqlite3.connect('your_database.db') # Путь к базе данных
1170 cursor = connection.cursor()
1171
1172 # Запрос для создания таблицы
1173 cursor.execute('''
1174 CREATE TABLE IF NOT EXISTS confirmed_numbers (
1175 id INTEGER PRIMARY KEY AUTOINCREMENT,
1176 number TEXT NOT NULL,
1177 time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
1178 );
1179 ''')
1180
1181 connection.commit() # Применяем изменения
1182 connection.close() # Закрываем соединение
1183
1184# Вызов функции для создания таблицы
1185create_table()
1186
1187# Функция для добавления номера в базу данных
1188def add_number_to_db(number):
1189 connection = sqlite3.connect('your_database.db') # Указывай путь к своей базе данных
1190 cursor = connection.cursor()
1191
1192 # Проверка на существование номера в базе данных (если нужно)
1193 cursor.execute("SELECT COUNT(*) FROM confirmed_numbers WHERE number = ?", (number,))
1194 if cursor.fetchone()[0] > 0:
1195 return False # Номер уже существует в базе данных
1196
1197 # Добавление номера в базу данных
1198 cursor.execute("INSERT INTO confirmed_numbers (number) VALUES (?)", (number,))
1199 connection.commit()
1200 connection.close()
1201 return True
1202
1203def add_number_to_db(number):
1204 connection = sqlite3.connect('your_database.db')
1205 cursor = connection.cursor()
1206
1207 # Проверяем, есть ли номер в базе
1208 cursor.execute("SELECT COUNT(*) FROM confirmed_numbers WHERE number = ?", (number,))
1209 if cursor.fetchone()[0] > 0:
1210 logging.info(f"Номер {number} уже есть в базе.")
1211 return False # Номер уже существует
1212
1213 # Добавляем номер
1214 cursor.execute("INSERT INTO confirmed_numbers (number) VALUES (?)", (number,))
1215 connection.commit()
1216 logging.info(f"✅ Номер {number} добавлен в базу.")
1217 connection.close()
1218 return True
1219
1220
1221@dp.callback_query_handler(lambda c: c.data == "admin_list")
1222async def admin_list(call: types.CallbackQuery):
1223 confirmed_numbers = get_confirmed_numbers() # Получаем подтвержденные номера
1224
1225 logging.info(f"Полученные данные о номерах: {confirmed_numbers}") # Логируем результат
1226
1227 # Проверка, что данные получены корректно
1228 if not confirmed_numbers or not isinstance(confirmed_numbers, list):
1229 await call.message.answer("⚠️ Ошибка: Не удалось загрузить подтвержденные номера.")
1230 await call.answer()
1231 return
1232
1233 if len(confirmed_numbers) == 0:
1234 await call.message.answer("⚠️ Подтвержденных номеров нет.")
1235 await call.answer()
1236 return
1237
1238 # Формируем список номеров
1239 try:
1240 list_text = "📜 **Список подтвержденных номеров:**\n\n"
1241 list_text += "\n".join([f"📞 {num[0]} - 🕒 {num[1]}" for num in confirmed_numbers])
1242 except (IndexError, TypeError):
1243 await call.message.answer("⚠️ Ошибка: Неверный формат данных о номерах.")
1244 await call.answer()
1245 return
1246
1247 # Отправляем список
1248 await call.message.answer(list_text, parse_mode="Markdown")
1249 await call.answer()
1250
1251
1252@dp.message_handler(commands=['admin'])
1253async def admin_menu(message: types.Message):
1254 if message.from_user.id not in ADMIN_USER_IDS:
1255 return await message.answer("❌ У вас нет доступа к админ-панели.")
1256 markup = InlineKeyboardMarkup().add(
1257 InlineKeyboardButton("📋 Список номеров", callback_data="admin_list"),
1258 InlineKeyboardButton("💰 Засчитать баланс", callback_data="admin_add_balance")
1259 )
1260 await message.answer("🔧 Админ-панель:", reply_markup=markup)
1261
1262@dp.callback_query_handler(lambda c: c.data == "admin_add_balance")
1263async def admin_add_balance_prompt(call: types.CallbackQuery):
1264 await call.message.answer("Введите номер и сумму через пробел (пример: 1234567890 10)")
1265 await BalanceInput.waiting_for_number_and_amount.set()
1266
1267# Обработчик для ввода номера и суммы
1268@dp.message_handler(state=BalanceInput.waiting_for_number_and_amount)
1269async def process_balance_input(message: types.Message, state: FSMContext):
1270 text = message.text.strip()
1271
1272 # Регулярное выражение для номера и суммы
1273 match = re.match(r"^(\+?\d{10,15})\s+(\d+)$", text)
1274 if not match:
1275 await message.reply("❌ Ошибка: некорректный формат. Введите номер и сумму через пробел.\nПример: `1234567890 10`", parse_mode="Markdown")
1276 return
1277
1278 phone_number, amount = match.groups()
1279 amount = float(amount)
1280
1281 # Создаем клавиатуру с кнопкой "Назад"
1282 back_button = InlineKeyboardMarkup()
1283 back_button.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
1284
1285 try:
1286 if phone_number not in user_numbers:
1287 await message.reply("❌ Ошибка: номер не найден.")
1288 return
1289
1290 user_id = user_numbers[phone_number]["user_id"]
1291 user_balances[user_id] = user_balances.get(user_id, 0.0) + amount
1292
1293 # Отправляем сообщение пользователю с кнопкой "Назад"
1294 await bot.send_message(user_id, f"✅ Вам начислено {amount:.2f} USD.", reply_markup=back_button)
1295
1296 # Отправляем сообщение обратно в чат с кнопкой "Назад"
1297 await message.answer(f"✅ Пользователю {user_id} начислено {amount:.2f} USD.", reply_markup=back_button)
1298
1299 except KeyError:
1300 await message.reply("❌ Ошибка: проблема с базой данных номеров.")
1301 except ValueError:
1302 await message.reply("❌ Ошибка: некорректная сумма.")
1303 finally:
1304 await state.finish()
1305
1306# Функция для добавления пользователя в базу данных
1307def add_user(user_id, username, referral_code=None, referred_by=None):
1308 conn = sqlite3.connect("users.db")
1309 cursor = conn.cursor()
1310 cursor.execute("INSERT INTO users (user_id, username, referral_code, referred_by) VALUES (?, ?, ?, ?)",
1311 (user_id, username, referral_code, referred_by))
1312 conn.commit()
1313 conn.close()
1314
1315# Функция для получения информации о пользователе
1316def get_user(user_id):
1317 conn = sqlite3.connect("users.db")
1318 cursor = conn.cursor()
1319 cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
1320 user = cursor.fetchone()
1321 conn.close()
1322 return user
1323
1324# Функция для обновления баланса пользователя
1325def update_balance(user_id, amount):
1326 conn = sqlite3.connect("users.db")
1327 cursor = conn.cursor()
1328 cursor.execute("UPDATE users SET balance = balance + ? WHERE user_id = ?", (amount, user_id))
1329 conn.commit()
1330 conn.close()
1331
1332# Главная кнопка меню с реферальной ссылкой
1333@dp.callback_query_handler(lambda c: c.data == "referral_link")
1334async def referral_link(call: types.CallbackQuery):
1335 user_id = call.from_user.id
1336 user = get_user(user_id)
1337
1338 if not user:
1339 # Если пользователь еще не зарегистрирован в базе, то добавляем его
1340 referral_code = generate_referral_code()
1341 add_user(user_id, call.from_user.username, referral_code)
1342
1343 referral_url = f"t.me/{BOT_USERNAME}?start={user[2]}" # Пример реферальной ссылки
1344 await call.message.answer(f"Ваша реферальная ссылка: {referral_url}")
1345
1346 await call.answer()
1347
1348from datetime import datetime
1349import sqlite3
1350
1351@dp.callback_query_handler(lambda c: c.data.startswith("code_entered_") or c.data.startswith("code_not_entered_"))
1352async def handle_code_confirmation(callback_query: types.CallbackQuery):
1353 number = callback_query.data.split("_")[-1]
1354 user_id = user_numbers.get(number, {}).get("user_id")
1355
1356 if not user_id:
1357 return await callback_query.answer("Ошибка: номер не найден!")
1358
1359 now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1360
1361 if callback_query.data.startswith("code_entered_"):
1362 save_confirmed_number(number, now)
1363 text = f"✅ Номер {number} подтверждён в {now}!"
1364 else:
1365 save_rejected_number(number, now)
1366 text = f"❌ Номер {number} отклонён в {now}!"
1367
1368 save_user(user_id)
1369
1370 # Отправка сообщения в админ-чат с кнопками
1371 admin_keyboard = InlineKeyboardMarkup().row(
1372 InlineKeyboardButton("📩 Взять номер", callback_data=f"take_{number}"),
1373 InlineKeyboardButton("⏭ Пропустить номер", callback_data=f"skip_{number}")
1374 )
1375
1376 await bot.send_message(ADMIN_GROUP_ID, text, reply_markup=admin_keyboard)
1377 await callback_query.answer("✅ Данные сохранены и статистика обновлена!")
1378
1379# === 🔥 Запуск бота ===
1380if __name__ == "__main__":
1381 logging.basicConfig(level=logging.INFO)
1382 executor.start_polling(dp, skip_updates=False)