Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import random
- import os
- import string
- import logging
- import re
- from database import get_all_users # Импортируем функцию
- from database import execute_query # или другой модуль, где эта функция
- from aiogram import Bot, Dispatcher, types
- from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message, CallbackQuery
- from aiogram.dispatcher.filters import Command # Импорт Command
- from aiogram.utils import executor
- import time
- from aiogram.dispatcher.filters import Text
- from apscheduler.schedulers.asyncio import AsyncIOScheduler
- from aiogram.dispatcher.filters.state import StatesGroup, State
- from aiogram.dispatcher.filters.state import State, StatesGroup
- class BalanceInput(StatesGroup):
- waiting_for_number_and_amount = State()
- from aiogram.dispatcher import FSMContext
- import sqlite3
- from datetime import datetime
- from datetime import timedelta
- from database import get_user_numbers
- from aiogram.types import ChatPermissions
- from collections import defaultdict
- from stats import user_stats, update_statistics # Импортируем из stats.py
- import pytz
- from aiogram.contrib.fsm_storage.memory import MemoryStorage
- import json
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
- # Функция для логирования user_stats и user_numbers
- def log_data(tag="DEBUG"):
- logging.info(f"🟡 {tag} | user_numbers = {json.dumps(user_numbers, default=str, indent=2)}")
- logging.info(f"🟡 {tag} | user_stats = {json.dumps(user_stats, default=str, indent=2)}")
- logging.basicConfig(level=logging.INFO)
- confirmed_numbers = []
- rejected_numbers = []
- # === 🔧 Настройки ===
- TOKEN = "" # Укажи свой токен
- ADMIN_GROUP_ID = -1002329021975 # ID группы админов
- REPORTS_CHAT_ID = -4795044900 # ID чата для отчётов (замени на нужный)
- ADMIN_USER_IDS = {8101813488, 987654321} # Выдача прав админа
- WITHDRAW_GROUP_ID = -1002290860098 # ID группы для заявок на вывод
- CHANNEL_USERNAME = "@legionWA_Rent" # ID вашего канала (например, "@your_channel")
- # Функция для подключения к базе данных
- def get_db_connection():
- return sqlite3.connect("stats.db")
- # Создание таблицы, если её нет
- with get_db_connection() as conn:
- cursor = conn.cursor()
- cursor.execute('''CREATE TABLE IF NOT EXISTS stats (
- user_id INTEGER PRIMARY KEY,
- confirmed INTEGER DEFAULT 0,
- skipped INTEGER DEFAULT 0,
- dropped INTEGER DEFAULT 0,
- errors INTEGER DEFAULT 0,
- all_numbers INTEGER DEFAULT 0,
- balance INTEGER DEFAULT 0,
- daily_earnings INTEGER DEFAULT 0)''')
- conn.commit()
- # Функция для получения статистики пользователя
- def get_user_stats(user_id):
- with get_db_connection() as conn:
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM stats WHERE user_id = ?", (user_id,))
- stats = cursor.fetchone()
- if not stats:
- cursor.execute("INSERT INTO stats (user_id) VALUES (?)", (user_id,))
- conn.commit()
- return get_user_stats(user_id)
- return stats
- # Функция обновления статистики
- def update_stat(user_id, column, value):
- with get_db_connection() as conn:
- cursor = conn.cursor()
- cursor.execute(f"UPDATE stats SET {column} = {column} + ? WHERE user_id = ?", (value, user_id))
- conn.commit()
- logging.info(f"User {user_id}: {column} updated by {value}")
- # Структура для хранения статистики пользователей
- user_stats = defaultdict(lambda: {"hold": 0, "failed": 0, "skipped": 0, "added": 0})
- user_numbers = {}
- # Функция обновления статистики
- async def update_user_stats(user_id):
- user_stats[user_id]['added'] += 1 # Увеличиваем количество добавленных номеров
- # Функция сброса статистики в 00:00 МСК
- async def reset_stats():
- while True:
- now = datetime.now()
- moscow_time = now + timedelta(hours=3) # Перевод на МСК
- reset_time = moscow_time.replace(hour=0, minute=0, second=0, microsecond=0)
- sleep_time = (reset_time - moscow_time).total_seconds()
- if sleep_time < 0:
- sleep_time += 86400 # Перекатываем на следующий день
- await asyncio.sleep(sleep_time)
- user_stats.clear()
- logging.info("Статистика сброшена")
- bot = Bot(token=TOKEN)
- storage = MemoryStorage() # Хранилище состояний
- dp = Dispatcher(bot, storage=storage) # Передаем storage в Dispatcher
- # Список пользователей и их балансов
- # Инициализация user_info как словаря для хранения информации о пользователе
- user_info = {}
- user_statistics = {}
- user_stats = {}
- user_balances = {} # Основной баланс
- user_bonus_balances = {} # Бонусный баланс
- user_numbers = {} # {номер: {"user_id": id, "msg_id": msg_id, "photo_sent": False, "confirmed": False}}
- # Словарь для хранения статистики пользователей
- user_stats = {}
- @dp.callback_query_handler(lambda c: c.data == "update_stats")
- async def refresh_stats(callback_query: types.CallbackQuery):
- user_id = callback_query.from_user.id
- # Проверяем, если статистика пользователя существует
- if user_id not in user_stats:
- await callback_query.answer("❌ Статистика не найдена.")
- return
- stats = user_stats[user_id]
- stats_message = (
- f"📊 Ваша статистика:\n"
- f"🔹 Добавлено номеров: {stats['added']}\n"
- f"🔹 В холде: {stats['hold']}\n"
- f"🔹 Пропущено номеров: {stats['skipped']}\n"
- f"🔹 Слетевших номеров: {stats['dropped']}\n"
- f"🔹 Слеты: {stats['failed']}"
- )
- # Отправляем сообщение с обновленной статистикой
- await callback_query.answer(stats_message)
- def get_user_stats(user_id: int):
- """ Функция получения статистики пользователя, если её нет — создаем. """
- if user_id not in user_stats:
- user_stats[user_id] = {
- "hold": 0, # В холде
- "failed": 0, # Слеты
- "skipped": 0, # Пропуски
- "dropped": 0, # Слеты
- "added": 0 # Добавлено
- }
- return user_stats[user_id]
- # Определение состояний
- class ReportForm(StatesGroup):
- waiting_for_number = State() # Состояние для ввода номера
- # === 🎛 Классы для состояний ===
- class ReportForm(StatesGroup):
- waiting_for_number = State()
- waiting_for_time = State()
- # === Подключение к базе данных ===
- def get_user_numbers(user_id, status):
- conn = sqlite3.connect("database.db")
- cursor = conn.cursor()
- cursor.execute("SELECT phone FROM user_numbers WHERE user_id=? AND status=?", (user_id, status))
- numbers = cursor.fetchall()
- conn.close()
- return [num[0] for num in numbers]
- # === Проверка на администратора ===
- def is_admin(user_id):
- return user_id in ADMIN_IDS
- #Словарь для хранения информации о подписке пользователей
- subscribed_users = {}
- # Проверка подписки на канал
- async def is_subscribed(user_id: int) -> bool:
- try:
- # Проверка, является ли пользователь подписчиком канала
- member = await bot.get_chat_member(CHANNEL_ID, user_id)
- # Если статус пользователя "member" или выше, то он подписан
- return member.status in ['member', 'administrator', 'creator']
- except Exception:
- return False
- #Инициализация базы данных SQLite
- def init_db():
- conn = sqlite3.connect("users.db")
- cursor = conn.cursor()
- cursor.execute('''CREATE TABLE IF NOT EXISTS users (
- user_id INTEGER PRIMARY KEY,
- username TEXT,
- referral_code TEXT,
- referred_by INTEGER,
- balance REAL DEFAULT 0.0
- )''')
- conn.commit()
- conn.close()
- #Функция для создания нового пользователя в базе данных
- def add_user(user_id, username, referral_code, referred_by=None):
- conn = sqlite3.connect('users.db')
- cursor = conn.cursor()
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS users (
- user_id INTEGER PRIMARY KEY,
- username TEXT,
- referral_code TEXT,
- referred_by INTEGER,
- balance REAL DEFAULT 0
- )
- """)
- cursor.execute("INSERT INTO users (user_id, username, referral_code, referred_by) VALUES (?, ?, ?, ?)",
- (user_id, username, referral_code, referred_by))
- conn.commit()
- conn.close()
- # Функция для получения информации о пользователе по ID
- def get_user(user_id):
- conn = sqlite3.connect('users.db')
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
- user = cursor.fetchone()
- conn.close()
- return user
- # Функция для получения пользователя по реферальному коду
- def get_user_by_referral_code(referral_code):
- conn = sqlite3.connect('users.db')
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE referral_code=?", (referral_code,))
- user = cursor.fetchone()
- conn.close()
- return user
- # Функция для обновления баланса пользователя
- def update_balance(user_id, amount):
- conn = sqlite3.connect('users.db')
- cursor = conn.cursor()
- cursor.execute("UPDATE users SET balance = balance + ? WHERE user_id=?", (amount, user_id))
- conn.commit()
- conn.close()
- # Генерация случайного реферального кода
- def generate_referral_code():
- return ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
- def get_all_users():
- conn = sqlite3.connect("bot_database.db")
- cursor = conn.cursor()
- cursor.execute("SELECT user_id FROM users")
- users = [row[0] for row in cursor.fetchall()]
- conn.close()
- return users
- # Обновленный main_menu с кнопкой "Статистика"
- def main_menu():
- menu = InlineKeyboardMarkup(row_width=2)
- menu.add(
- InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
- InlineKeyboardButton("📊 Статистика", callback_data="stats_today")
- )
- menu.add(
- InlineKeyboardButton("📋 Отчёт", callback_data="send_report"),
- InlineKeyboardButton("💰 Баланс", callback_data="withdraw")
- )
- menu.add(
- InlineKeyboardButton("📈 Реферальная система", callback_data="referral_system"),
- InlineKeyboardButton("❓ FAQ", callback_data="faq")
- )
- return menu
- # === 📌 Обработчик команды /start ===
- @dp.message_handler(commands=['start'])
- async def start(message: types.Message):
- user_id = message.from_user.id
- if user_id not in subscribed_users or not subscribed_users[user_id]:
- keyboard = InlineKeyboardMarkup()
- keyboard.add(InlineKeyboardButton("🔗 Подписаться на канал", url="https://t.me/legionWA_Rent"))
- keyboard.add(InlineKeyboardButton("🔄 Проверить подписку", callback_data="check_subscription"))
- # Запрашиваем подписку перед тем, как показывать главное меню
- await message.answer("Для того, чтобы продолжить, подпишитесь на наш канал:", reply_markup=keyboard)
- subscribed_users[user_id] = False
- else:
- # Если подписка выполнена, показываем главное меню
- await message.answer("🚀 Добро пожаловать! Выберите действие:", reply_markup=main_menu())
- @dp.message_handler(state=ReportForm.waiting_for_number)
- async def get_number(message: types.Message, state: FSMContext):
- if not message.text.startswith("+7") or not message.text[1:].isdigit():
- await message.answer("❌ Неверный формат номера! Введите в формате: `+7XXXXXXXXXX`", parse_mode="Markdown")
- return
- await state.update_data(number=message.text)
- await message.answer("⏰ Теперь введите время связки (МСК) в формате `HH:MM`")
- await ReportForm.waiting_for_time.set()
- @dp.message_handler(state=ReportForm.waiting_for_time)
- async def get_time(message: types.Message, state: FSMContext):
- user_data = await state.get_data()
- number = user_data["number"]
- time = message.text.strip()
- if not time.replace(":", "").isdigit() or len(time) not in [4, 5]:
- await message.answer("❌ Неверный формат! Введите время в формате `HH:MM`")
- return
- report_text = f"📢 Новый отчёт!\n📞 Номер: {number}\n⏰ Время связки (МСК): {time}"
- await bot.send_message(REPORTS_CHAT_ID, report_text)
- await message.answer("✅ Отчёт отправлен администраторам!", reply_markup=main_menu())
- await state.finish()
- # Обработчик команды /start с реферальной ссылкой
- @dp.message_handler(commands=['start'])
- async def start(message: types.Message):
- referral_code = message.text.split()[-1] # Получаем реферальный код
- user_id = message.from_user.id
- # Проверяем, если пользователь перешел по реферальной ссылке
- if referral_code:
- referred_by_user = get_user_by_referral_code(referral_code)
- if referred_by_user:
- add_user(user_id, message.from_user.username, generate_referral_code(), referred_by=referred_by_user[0])
- await message.answer(f"Вы зарегистрированы через реферальную ссылку @{referred_by_user[1]}.")
- await message.answer("Добро пожаловать в систему!")
- # Отчисляем 10% владельцу ссылки
- referral_bonus = 10 # 10% от суммы, которую мы хотим начислить
- update_balance(referred_by_user[0], referral_bonus)
- # Отправляем владельцу ссылки информацию о новом пользователе
- await bot.send_message(referred_by_user[0], f"Получено {referral_bonus} долларов за реферала @{message.from_user.username}!")
- else:
- await message.answer("❌ Неверная реферальная ссылка.")
- else:
- # Если реферальной ссылки нет, то просто генерируем новый код
- referral_code = generate_referral_code()
- add_user(user_id, message.from_user.username, referral_code)
- await message.answer("Привет, добро пожаловать в наш бот! Используйте /referral для получения своей реферальной ссылки.")
- @dp.callback_query_handler(lambda c: c.data == "referral_system")
- async def referral_system(call: types.CallbackQuery):
- user_id = call.from_user.id
- # Получаем username бота
- bot_username = (await bot.get_me()).username
- if bot_username:
- referral_link = f"https://t.me/{bot_username}?start={user_id}" # Генерируем ссылку для пользователя
- else:
- referral_link = "Ошибка: имя пользователя бота не настроено."
- # Создаем клавиатуру с кнопкой "Назад"
- keyboard = InlineKeyboardMarkup(row_width=1)
- keyboard.add(
- InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
- )
- # Редактируем текущее сообщение, а не отправляем новое
- await call.message.edit_text(
- f"Если вы пригласите своего друга, то будете получать с каждого его отстоявшего номера по 10%.\n\n"
- f"Вот ваша реферальная ссылка: {referral_link}",
- reply_markup=keyboard
- )
- await call.answer() # Закрываем индикатор загрузки
- @dp.callback_query_handler(lambda c: c.data == "stats_today")
- async def show_stats(callback_query: types.CallbackQuery):
- user_id = callback_query.from_user.id
- stats = user_stats.get(user_id, {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0})
- # Логируем статистику перед формированием текста
- logging.info(f"Показ статистики для пользователя {user_id}: {stats}")
- # Формируем текст с актуальной статистикой
- text = (
- f"📊 *Ваша статистика:*\n"
- f"├ В холде: {stats['hold']}\n"
- f"├ Слетов: {stats['failed']}\n"
- f"├ Пропущено: {stats['skipped']}\n"
- f"├ Слетело: {stats['dropped']}\n"
- f"└ Добавлено: {stats['added']}\n" # Добавлена строка для статистики по добавленным номерам
- )
- # Обновляем клавиатуру
- keyboard = InlineKeyboardMarkup().add(
- InlineKeyboardButton("🔄 Обновить статистику", callback_data="update_stats"),
- InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
- )
- await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode="Markdown")
- await callback_query.answer()
- # Обновление статистики вручную
- @dp.callback_query_handler(lambda c: c.data == "update_stats")
- async def refresh_stats(callback_query: types.CallbackQuery):
- user_id = callback_query.from_user.id
- # Получаем статистику пользователя
- stats = user_stats.get(user_id, {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0}) # Добавлено "added"
- # Формируем текст с актуальной статистикой
- text = (
- f"📊 *Ваша статистика:*\n"
- f"├ В холде: {stats['hold']}\n"
- f"├ Слетов: {stats['failed']}\n"
- f"├ Пропущено: {stats['skipped']}\n"
- f"├ Слетело: {stats['dropped']}\n"
- f"└ Добавлено: {stats['added']}\n" # Добавлена строка для статистики по добавленным номерам
- )
- # Обновляем клавиатуру
- keyboard = InlineKeyboardMarkup().add(
- InlineKeyboardButton("🔄 Обновить статистику", callback_data="update_stats"),
- InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
- )
- # Обновляем сообщение с актуальной статистикой
- await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode="Markdown")
- await callback_query.answer() # Подтверждаем обработку кнопки
- # === Обработчик проверки подписки ===
- @dp.callback_query_handler(lambda c: c.data == "check_subscription")
- async def check_subscription(call: types.CallbackQuery):
- user_id = call.from_user.id
- try:
- chat_member = await bot.get_chat_member(CHANNEL_USERNAME, user_id)
- if chat_member.status in ['member', 'administrator', 'creator']:
- subscribed_users[user_id] = True
- # Кнопка для начала работы
- start_keyboard = InlineKeyboardMarkup().add(
- InlineKeyboardButton("🚀 Начать работу", callback_data="start_work")
- )
- await call.message.answer("✅ Вы подписаны на канал. Теперь можно использовать все функции бота.", reply_markup=start_keyboard)
- else:
- await call.message.answer("❌ Вы не подписаны на канал. Пожалуйста, подпишитесь, чтобы продолжить.")
- except Exception as e:
- await call.message.answer(f"❌ Ошибка при проверке подписки: {e}")
- await call.answer()
- # === 📌 Обработчик кнопки "Начать работу" ===
- @dp.callback_query_handler(lambda c: c.data == "start_work")
- async def start_work(callback_query: types.CallbackQuery):
- # Действия, которые выполняются при нажатии на кнопку "Начать работу"
- # Подтверждение действия
- await callback_query.answer("👨💻 Вы начали работу!")
- # Отправляем главное меню с кнопкой "Статистика"
- await callback_query.message.edit_text("🚀 Добро пожаловать! Выберите действие:", reply_markup=main_menu())
- #=== 📤 Сдать номер ===
- # Обработчик нажатия кнопки "submit_number"
- @dp.callback_query_handler(lambda c: c.data == "submit_number")
- async def submit_number(call: types.CallbackQuery):
- # Создаем клавиатуру с кнопкой "Назад"
- keyboard = InlineKeyboardMarkup(row_width=1)
- keyboard.add(
- InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
- )
- # Редактируем текущее сообщение вместо отправки нового
- await call.message.edit_text("📲 Введите номер в формате: `+7XXXXXXXXXX`", parse_mode="Markdown", reply_markup=keyboard)
- await call.answer()
- # Обработчик на ввод номера
- @dp.message_handler(lambda message: message.text.startswith("+7"))
- async def receive_number(message: types.Message):
- user_id = message.from_user.id
- username = message.from_user.username or "Без имени"
- number = message.text.strip()
- logging.info(f"📌 Пользователь {user_id} ({username}) ввел номер: {number}")
- # Проверка на уникальность номера
- if number in user_numbers and user_numbers[number].get("confirmed"):
- await message.answer("❌ Этот номер уже подтвержден.")
- return
- # Добавляем номер в user_numbers с флагом, что он еще не подтвержден
- user_numbers[number] = {"user_id": user_id, "confirmed": False}
- admin_message = f"📞 *Новый номер от @{username} (ID: `{user_id}`):*\n📲 `{number}`"
- # Создание кнопок для администратора
- keyboard = InlineKeyboardMarkup(row_width=2)
- keyboard.add(
- InlineKeyboardButton("Взять номер", callback_data=f"take_number_{number}"),
- InlineKeyboardButton("Пропустить", callback_data=f"skip_number_{number}")
- )
- try:
- # Отправляем сообщение в группу администраторов
- msg = await bot.send_message(ADMIN_GROUP_ID, admin_message, parse_mode="Markdown", reply_markup=keyboard)
- user_numbers[number]["msg_id"] = msg.message_id
- logging.info(f"✅ Номер {number} отправлен в очередь для администратора.")
- await message.answer("✅ Номер отправлен в очередь, ожидайте.")
- except Exception as e:
- await message.answer("❌ Ошибка отправки номера. Проверь настройки группы.")
- logging.error(f"Ошибка отправки в группу: {e}")
- # Обработчик нажатия кнопки "Взять номер"
- @dp.callback_query_handler(lambda c: c.data.startswith("take_number_"))
- async def take_number(call: types.CallbackQuery):
- number = call.data.split("_")[-1]
- user_info = user_numbers.get(number)
- if not user_info:
- await call.answer("❌ Номер не найден.")
- return
- user_id = user_info["user_id"]
- # Логируем информацию о пользователе
- logging.info(f"Номер {number} найден для пользователя {user_id}. Обновляем его статус.")
- # Обновляем статус номера на "added"
- user_info["status"] = "added"
- logging.info(f"Статус номера {number} изменён на 'added'.")
- # Обновляем статистику пользователя для действия "added"
- logging.info(f"Обновляем статистику для пользователя {user_id} с действием 'added'.")
- update_statistics(user_id, "added")
- logging.info(f"Статистика для пользователя {user_id} обновлена после добавления номера {number}.")
- # Уведомляем пользователя о том, что номер добавлен
- await bot.send_message(user_id, f"✅ Ваш номер {number} был добавлен в систему.")
- # Логирование действия
- logging.info(f"Номер {number} был добавлен для пользователя {user_id}.")
- # Отправляем уведомление администратору
- await bot.send_message(ADMIN_GROUP_ID, f"✅ Номер {number} был добавлен и принят в систему.")
- # Удаляем сообщение с кнопками
- await call.message.delete()
- # Отвечаем на callback
- await call.answer()
- # Обработчик для пропуска номера
- @dp.callback_query_handler(lambda c: c.data.startswith("skip_number_"))
- async def skip_number(call: types.CallbackQuery):
- number = call.data.split("_")[-1]
- user_info = user_numbers.get(number)
- if not user_info:
- await call.answer("❌ Номер не найден.")
- return
- # Удаляем сообщение с номером
- await bot.delete_message(chat_id=ADMIN_GROUP_ID, message_id=user_info["msg_id"])
- # Уведомляем администратора о пропуске
- await bot.send_message(ADMIN_GROUP_ID, f"❌ Номер {number} был пропущен.")
- # Отвечаем на callback
- await call.answer()
- # Удаляем номер из системы
- del user_numbers[number]
- # Обработчик для получения номера от администратора
- @dp.message_handler(content_types=["photo"])
- async def admin_reply_photo(message: types.Message):
- if not message.reply_to_message or message.chat.id != ADMIN_GROUP_ID:
- return
- text = message.reply_to_message.text or ""
- number = re.search(r"\+7\d{10}", text)
- if not number:
- await message.reply("❌ Ошибка: номер не найден в сообщении.")
- return
- number = number.group(0)
- if number not in user_numbers:
- user_numbers[number] = {"user_id": message.from_user.id, "status": "pending"}
- user_id = user_numbers[number]["user_id"]
- keyboard = InlineKeyboardMarkup()
- keyboard.add(
- InlineKeyboardButton("✅ Код введен", callback_data=f"code_entered_{number}"),
- InlineKeyboardButton("❌ Код не введен", callback_data=f"code_not_entered_{number}")
- )
- try:
- photo = message.photo[-1].file_id
- msg = await bot.send_photo(user_id, photo=photo, caption="🔑 Введите полученный код:", reply_markup=keyboard)
- user_numbers[number]["msg_id"] = msg.message_id
- user_numbers[number]["photo_sent"] = True
- await message.reply("✅ Код отправлен пользователю.")
- except Exception as e:
- logging.exception(f"Ошибка отправки фото пользователю: {e}")
- await message.reply("❌ Ошибка отправки фото пользователю.")
- # Функции для извлечения номера
- def normalize_number(number: str) -> str:
- """Приводит номер к единому формату +7XXXXXXXXXX"""
- number = number.replace(" ", "").strip()
- if number.startswith("8"):
- number = "+7" + number[1:]
- return number
- def get_number_from_message(message: types.Message) -> str:
- """Извлекает номер телефона из ответа администратора."""
- if message.reply_to_message:
- match = re.search(r"\+7\d{10}", message.reply_to_message.text or "")
- return match.group(0) if match else None
- return None
- @dp.callback_query_handler(lambda c: c.data == "send_report")
- async def send_report(call: types.CallbackQuery):
- # Ссылка на чат для отчетов
- report_chat_link = "https://t.me/report_legion" # Укажите правильную ссылку на ваш чат
- # Создаем клавиатуру с кнопкой "Назад"
- keyboard = InlineKeyboardMarkup(row_width=1)
- keyboard.add(
- InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
- )
- # Редактируем текущее сообщение, а не отправляем новое
- await call.message.edit_text(
- f"📌 Для отправки отчета, пожалуйста, перейдите в [чат для отчетов]({report_chat_link})",
- parse_mode="Markdown",
- reply_markup=keyboard
- )
- # Завершаем обработку callback
- await call.answer()
- @dp.message_handler(commands=['get_chat_id'])
- async def get_chat_id(message: types.Message):
- chat_id = message.chat.id
- await message.answer(f"Chat ID: {chat_id}")
- @dp.message_handler(Command('ban'))
- async def ban_user(message: types.Message):
- """Бан пользователя с указанием времени и причины."""
- # Проверяем, является ли пользователь администратором
- if message.chat.type != "private":
- admins = await bot.get_chat_administrators(message.chat.id)
- if message.from_user.id not in [admin.user.id for admin in admins]:
- await message.answer("❌ Вы не являетесь администратором.")
- return
- # Разбираем команду, ожидаем формат: /ban @username 10m причина
- parts = message.text.split(' ')
- if len(parts) < 3:
- await message.answer("❌ Неверный формат команды. Используйте: `/ban @username <время> <причина>`", parse_mode="Markdown")
- return
- username = parts[1] # @username
- time_duration = parts[2] # Время (например, 10m, 1h, 1d)
- reason = " ".join(parts[3:]) if len(parts) > 3 else "Не указана" # Причина (если указана)
- # Проверка на правильность времени
- try:
- if time_duration[-1] == 'm': # минуты
- ban_time = timedelta(minutes=int(time_duration[:-1]))
- elif time_duration[-1] == 'h': # часы
- ban_time = timedelta(hours=int(time_duration[:-1]))
- elif time_duration[-1] == 'd': # дни
- ban_time = timedelta(days=int(time_duration[:-1]))
- else:
- raise ValueError
- except ValueError:
- await message.answer("❌ Неверный формат времени. Используйте 'm' для минут, 'h' для часов, 'd' для дней.")
- return
- # Получаем ID пользователя по username
- try:
- user = await bot.get_chat_member(message.chat.id, username)
- user_id = user.user.id
- except Exception as e:
- await message.answer(f"❌ Ошибка при получении информации о пользователе: {str(e)}")
- return
- # Дата окончания бана
- ban_until = datetime.now(pytz.UTC) + ban_time
- try:
- # Баним пользователя на определенное время
- await bot.ban_chat_member(chat_id=message.chat.id, user_id=user_id, until_date=ban_until)
- await message.answer(f"✅ Пользователь {username} забанен на {time_duration}. Причина: {reason}")
- except Exception as e:
- await message.answer(f"❌ Не удалось забанить пользователя. Ошибка: {str(e)}")
- @dp.message_handler(Command('unban'))
- async def unban_user(message: types.Message):
- """Разбан пользователя."""
- # Проверяем, является ли пользователь администратором
- if message.chat.type != "private":
- admins = await bot.get_chat_administrators(message.chat.id)
- if message.from_user.id not in [admin.user.id for admin in admins]:
- await message.answer("❌ Вы не являетесь администратором.")
- return
- # Разбираем команду, ожидаем формат: /unban @username
- parts = message.text.split(' ')
- if len(parts) < 2:
- await message.answer("❌ Неверный формат команды. Используйте: `/unban @username`", parse_mode="Markdown")
- return
- username = parts[1] # @username
- # Получаем ID пользователя по username
- try:
- user = await bot.get_chat_member(message.chat.id, username)
- user_id = user.user.id
- except Exception as e:
- await message.answer(f"❌ Ошибка при получении информации о пользователе: {str(e)}")
- return
- try:
- # Разбаниваем пользователя
- await bot.unban_chat_member(chat_id=message.chat.id, user_id=user_id, only_if_banned=True)
- await message.answer(f"✅ Пользователь {username} был разбанен.")
- except Exception as e:
- await message.answer(f"❌ Не удалось разбанить пользователя. Ошибка: {str(e)}")
- #Обработка кнопки "Вернуться в меню"
- # Основное меню
- def main_menu():
- menu = InlineKeyboardMarkup(row_width=2)
- # Первый ряд: две кнопки
- menu.add(
- InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
- InlineKeyboardButton("📋 Отчёт", callback_data="send_report")
- )
- # Второй ряд: две кнопки
- menu.add(
- InlineKeyboardButton("💰 Вывести", callback_data="withdraw"),
- InlineKeyboardButton("📈 Реферальная система", callback_data="referral_system")
- )
- # Третий ряд: одна кнопка
- menu.add(
- InlineKeyboardButton("❓ FAQ", callback_data="faq")
- )
- return menu # Возвращаем сформированное меню
- # Отправляем главное меню
- async def main():
- result = await some_coroutine()
- print(result)
- @dp.callback_query_handler(lambda c: c.data.startswith("code_"))
- async def handle_code_confirmation(callback_query: types.CallbackQuery):
- action, number = callback_query.data.split("_")[-2], callback_query.data.split("_")[-1]
- logging.info(f"Кнопка нажата: {callback_query.data}")
- if number not in user_numbers:
- logging.error(f"❌ Ошибка: номер {number} не найден в системе.")
- return await callback_query.answer("❌ Ошибка: номер не найден в системе.")
- user_info = user_numbers[number]
- user_id = user_info["user_id"]
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- user_info["confirmed_time"] = datetime.now()
- # Обновляем статус номера в холд
- if action == "entered":
- # Здесь будет передача номера в холд
- user_info["status"] = "hold" # Помечаем номер как "hold"
- logging.info(f"Номер {number} добавлен в холд.")
- elif action == "not_entered":
- user_info["status"] = "rejected"
- logging.info(f"Обновлен статус номера: {number} для пользователя: {user_id}, статус: {user_info['status']}")
- # Обновляем статистику для пользователя
- update_statistics(user_id, action) # Здесь обновляется статистика с действием, например "hold"
- # Создаем клавиатуру с кнопкой "Назад"
- back_button = InlineKeyboardMarkup().add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
- # Отправляем соответствующие сообщения пользователю
- if action == "entered":
- await callback_query.answer("✅ Код подтвержден.")
- await bot.send_message(user_info["user_id"], "✅ Ваш код был успешно подтвержден и теперь находится в холде.", reply_markup=back_button)
- text = f"✅ Код подтвержден и добавлен в холд!\n📲 Номер: {number}\n⏰ Время: {timestamp}"
- elif action == "not_entered":
- await callback_query.answer("❌ Код не введен.")
- await bot.send_message(user_info["user_id"], "❌ Ваш код не был подтвержден.", reply_markup=back_button)
- text = f"❌ Код не введен!\n📲 Номер: {number}\n⏰ Время: {timestamp}"
- # Кнопки для админов
- skip_button = InlineKeyboardButton("⏭️ Пропустить номер", callback_data=f"skip_{number}")
- drop_button = InlineKeyboardButton("⚠️ Слет", callback_data=f"drop_{number}")
- action_keyboard = InlineKeyboardMarkup().add(skip_button, drop_button)
- # Отправка сообщения в группу администраторов с кнопками
- await bot.send_message(ADMIN_GROUP_ID, text, reply_markup=action_keyboard)
- # Обновление кнопок для текущего сообщения
- await callback_query.message.edit_reply_markup()
- # Функция для записи данных в таблицу (или базу данных)
- async def log_action_to_db(user_id: int, action: str, timestamp: str):
- """Асинхронно записываем статистику в базу данных."""
- db_data = {
- "user_id": user_id,
- "action": action,
- "timestamp": timestamp,
- "hold": user_stats[user_id]["hold"],
- "failed": user_stats[user_id]["failed"],
- "skipped": user_stats[user_id]["skipped"],
- "dropped": user_stats[user_id]["dropped"],
- "added": user_stats[user_id]["added"],
- }
- # Пример асинхронной записи в базу данных
- await db.insert_user_data(db_data) # Замените на вашу асинхронную функцию
- logging.info(f"Статистика для user_id={user_id} записана в БД: {db_data}")
- async def handle_code_entered(callback_query: types.CallbackQuery):
- number = callback_query.data.split("_")[-1]
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Используйте datetime.now()
- logging.info(f"📌 Код введен для номера: {number}")
- # Проверяем, существует ли номер в системе
- if number not in user_numbers:
- logging.error(f"❌ Номер {number} не найден в системе.")
- return await callback_query.answer("❌ Номер не найден в системе.")
- # Получаем информацию о пользователе по номеру
- user_info = user_numbers[number]
- user_id = user_info["user_id"]
- # Если пользователь еще не добавлен в статистику, создаем запись
- if user_id not in user_stats:
- logging.warning(f"⚠️ Статистика для пользователя {user_id} не найдена, создаём запись.")
- user_stats[user_id] = {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0}
- # Логируем информацию о пользователе
- logging.info(f"Найден пользователь: {user_id}, статус: {user_info['status']}")
- # Обновляем статус номера на "hold"
- user_info["status"] = "hold"
- logging.info(f"✅ Обновлено: user_id={user_id}, статус={user_info['status']}")
- # Обновляем статистику с действием 'hold' (в холде)
- update_statistics(user_id, "hold") # Добавляем статистику для действия "hold"
- logging.info(f"Номер {number} добавлен в холд для пользователя {user_id}. Статистика обновлена.")
- # Запись статистики в базу данных после обновления
- log_action_to_db(user_id, "hold", timestamp) # Записываем в базу
- # Отправляем сообщение пользователю и администратору
- await bot.send_message(user_id, f"✅ Ваш номер в обработке.\n📞 Номер: {number}\n⏰ Время: {timestamp}")
- await bot.send_message("ADMIN_GROUP_ID", f"✅ Номер {number} добавлен в холд.\n⏰ Время: {timestamp}")
- # Отвечаем на запрос callback
- await callback_query.answer("✅ Код подтвержден, номер добавлен в холд.")
- await callback_query.message.edit_reply_markup()
- @dp.callback_query_handler(lambda c: c.data.startswith("drop_"))
- async def handle_drop(callback_query: types.CallbackQuery):
- number = callback_query.data.split("_")[-1]
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- log_data("BEFORE DROP") # 🔥 Логируем перед выполнением
- # Проверяем, есть ли номер в системе
- if number not in user_numbers:
- return await callback_query.answer("❌ Номер не найден в системе.")
- # Получаем user_id и информацию о номере
- user_info = user_numbers[number]
- user_id = user_info["user_id"]
- # 🔥 Исправление: Если user_stats[user_id] не существует — создаем!
- if user_id not in user_stats:
- logging.warning(f"⚠️ Пользователь {user_id} отсутствует в user_stats! Создаю запись...")
- user_stats[user_id] = {
- "hold": 0,
- "failed": 0,
- "skipped": 0,
- "dropped": 0,
- }
- # 🔍 Проверяем, был ли номер в холде
- if user_info.get("status") != "hold":
- logging.warning(f"⚠️ Попытка удалить номер {number}, но он не был в холде!")
- return await callback_query.answer("❌ Ошибка: этот номер не был в холде!")
- # Уменьшаем счётчик "В холде" и увеличиваем "Слеты"
- if user_stats[user_id]["hold"] > 0:
- user_stats[user_id]["hold"] -= 1
- user_stats[user_id]["dropped"] += 1
- # Обновляем статус номера
- user_numbers[number]["status"] = "dropped"
- log_data("AFTER DROP") # 🔥 Логируем после выполнения
- # Отправляем уведомления
- await bot.send_message(user_id, f"⚠️ Ваш номер слетел.\n📞 Номер: {number}\n⏰ Время: {timestamp}")
- await bot.send_message(ADMIN_GROUP_ID, f"⚠️ Номер {number} слетел!\n⏰ Время: {timestamp}")
- await callback_query.answer("✅ Слет зафиксирован, статистика обновлена.")
- await callback_query.message.edit_reply_markup()
- @dp.callback_query_handler(lambda c: c.data == "back_to_main_menu")
- async def back_to_main_menu(call: types.CallbackQuery):
- # Создаем клавиатуру с двумя столбцами
- keyboard = InlineKeyboardMarkup(row_width=2) # Устанавливаем 2 кнопки в строке
- # Добавляем кнопки
- keyboard.add(
- InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
- InlineKeyboardButton("📊 Статистика", callback_data="stats_today"),
- InlineKeyboardButton("🎁 Реферальная система", callback_data="referral_system"),
- InlineKeyboardButton("📌 Отправить отчет", callback_data="send_report"),
- InlineKeyboardButton("💰 Баланс", callback_data="withdraw"),
- InlineKeyboardButton("❓ FAQ", callback_data="faq")
- )
- # Отправляем сообщение с клавиатурой
- await call.message.edit_text("🏠 Главное меню:", reply_markup=keyboard)
- await call.answer()
- logging.info(f"📊 user_numbers ДО обработки: {user_numbers}")
- logging.info(f"📊 user_stats ДО обработки: {user_stats}")
- # Функция обновления статистики
- async def update_user_stats(user_id):
- user_stats[user_id]['hold'] += 1 # Увеличиваем количество номеров в холде
- # Обработчик кнопки "Код введен"
- @dp.callback_query_handler(lambda c: c.data.startswith("code_entered_"))
- async def handle_code_entered(callback_query: types.CallbackQuery):
- user_id = callback_query.from_user.id
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- update_stat(user_id, "confirmed", 1)
- log_action_to_db(user_id, "code_entered", timestamp)
- await bot.send_message(user_id, f"✅ Ваш номер в обработке.\n⏰ Время: {timestamp}")
- await bot.send_message("ADMIN_GROUP_ID", f"✅ Номер добавлен в Подтвержденные.\n⏰ Время: {timestamp}")
- await callback_query.answer("✅ Код подтвержден, номер добавлен в Подтвержденные")
- await callback_query.message.edit_reply_markup()
- #=== 💰 Вывести средства ===
- @dp.callback_query_handler(lambda c: c.data == "withdraw")
- async def withdraw_request(call: types.CallbackQuery):
- user_id = call.from_user.id
- balance = user_balances.get(user_id, 0) # Основной баланс
- bonus_balance = user_bonus_balances.get(user_id, 0) # Бонусный баланс
- if balance <= 0 and bonus_balance <= 0:
- await call.message.edit_text("❌ У вас нет средств на вывод.", reply_markup=InlineKeyboardMarkup().add(
- InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
- ))
- await call.answer()
- return
- # Создаем клавиатуру с кнопками вывода
- keyboard = InlineKeyboardMarkup(row_width=1)
- if balance > 0:
- keyboard.add(InlineKeyboardButton("💸 Вывести с основного баланса", callback_data="withdraw_main"))
- if bonus_balance > 0:
- keyboard.add(InlineKeyboardButton("🎁 Вывести с бонусного баланса", callback_data="withdraw_bonus"))
- keyboard.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
- # Отображаем балансы и клавиатуру
- await call.message.edit_text(
- f"💰 *Ваш баланс:*\n"
- f"💵 Основной баланс: {balance} USD\n"
- f"🎁 Бонусный баланс: {bonus_balance} USD",
- parse_mode="Markdown",
- reply_markup=keyboard
- )
- await call.answer()
- # Обработчик выбора вывода с основного баланса
- @dp.callback_query_handler(lambda c: c.data == "withdraw_main")
- async def withdraw_main(call: types.CallbackQuery):
- await start_withdraw(call, "main")
- # Обработчик выбора вывода с бонусного баланса
- @dp.callback_query_handler(lambda c: c.data == "withdraw_bonus")
- async def withdraw_bonus(call: types.CallbackQuery):
- await start_withdraw(call, "bonus")
- # Универсальный обработчик начала вывода
- async def start_withdraw(call: types.CallbackQuery, balance_type: str):
- user_id = call.from_user.id
- balance = user_balances.get(user_id, 0) if balance_type == "main" else user_bonus_balances.get(user_id, 0)
- if balance <= 0:
- await call.message.edit_text("❌ Недостаточно средств для вывода.", reply_markup=InlineKeyboardMarkup().add(
- InlineKeyboardButton("⬅️ Назад", callback_data="withdraw")
- ))
- await call.answer()
- return
- keyboard = InlineKeyboardMarkup().add(
- InlineKeyboardButton("❌ Отменить", callback_data="withdraw")
- )
- await call.message.edit_text(
- f"💰 Введите сумму для вывода в долларах ({'основной' if balance_type == 'main' else 'бонусный'} баланс):",
- reply_markup=keyboard
- )
- await call.answer()
- # Сохраняем тип баланса, чтобы знать, откуда списывать средства
- user_withdraw_requests[user_id] = balance_type
- # Обработчик ввода суммы для вывода
- user_withdraw_requests = {} # Временное хранилище запросов вывода
- @dp.message_handler(lambda message: message.text.replace('.', '', 1).isdigit())
- async def handle_withdraw_amount(message: types.Message):
- user_id = message.from_user.id
- amount = float(message.text)
- # Определяем, с какого баланса идет вывод
- balance_type = user_withdraw_requests.get(user_id)
- if not balance_type:
- await message.answer("❌ Ошибка: неизвестный источник вывода.")
- return
- balance = user_balances.get(user_id, 0) if balance_type == "main" else user_bonus_balances.get(user_id, 0)
- if amount > balance:
- await message.answer("❌ У вас недостаточно средств для вывода.")
- return
- if amount <= 0:
- await message.answer("❌ Сумма вывода должна быть положительной.")
- return
- # Обновляем баланс пользователя
- if balance_type == "main":
- user_balances[user_id] -= amount
- else:
- user_bonus_balances[user_id] -= amount
- # Отправляем заявку на вывод в группу администраторов
- await bot.send_message(
- WITHDRAW_GROUP_ID,
- f"💰 @{message.from_user.username} (ID: {user_id}) хочет вывести {amount} USD с {'основного' if balance_type == 'main' else 'бонусного'} баланса."
- )
- keyboard = InlineKeyboardMarkup().add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
- await message.answer(f"✅ Запрос на вывод {amount} USD отправлен на проверку.", reply_markup=keyboard)
- # Удаляем временные данные
- user_withdraw_requests.pop(user_id, None)
- # === ❓ FAQ ===
- @dp.callback_query_handler(lambda c: c.data == "faq")
- async def faq(call: types.CallbackQuery):
- faq_text = """**❓ FAQ ❓**
- 1️⃣ Мы не несем ответственность за аккаунты.
- 2️⃣ В случае скама офиса, выплаты не гарантируются.
- 3️⃣ Если номер отстоял 59 мин вместо 1 часа — оплаты не будет.
- 4️⃣ Выплаты в течение 7 дней.
- 5️⃣ Постоянный «Скип» может привести к блокировке.
- 6️⃣ Принимаются только РФ номера 6+ месяцев.
- 7️⃣ Администрация имеет право исключить вас без объяснений."""
- # Создаем инлайн кнопку "⬅️ Назад"
- keyboard = InlineKeyboardMarkup()
- keyboard.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
- # Редактируем текущее сообщение вместо отправки нового
- await call.message.edit_text(faq_text, parse_mode="Markdown", reply_markup=keyboard)
- await call.answer()
- @dp.message_handler(commands=["broadcast"])
- async def start_broadcast(message: types.Message):
- if message.from_user.id not in ADMIN_USER_IDS:
- return await message.answer("❌ У вас нет прав для рассылки.")
- await message.answer("Введите текст для рассылки:")
- await dp.current_state(user=message.from_user.id).set_state("waiting_for_broadcast")
- @dp.message_handler(state="waiting_for_broadcast")
- async def send_broadcast(message: types.Message, state):
- text = message.text
- users = get_all_users()
- sent_count = 0
- failed_count = 0
- for user_id in users:
- try:
- await bot.send_message(user_id, text)
- sent_count += 1
- await asyncio.sleep(0.5) # Антиспам-задержка
- except Exception:
- failed_count += 1
- await message.answer(f"✅ Рассылка завершена! Отправлено: {sent_count}, Ошибок: {failed_count}.")
- await state.finish()
- # Убедитесь, что эта функция не принимает никаких аргументов
- def admin_panel():
- menu = InlineKeyboardMarkup(row_width=2)
- menu.add(
- InlineKeyboardButton("📊 Общая статистика", callback_data="admin_stats"),
- InlineKeyboardButton("📜 Список", callback_data="admin_list"), # список
- #InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
- #InlineKeyboardButton("💰 Вывести", callback_data="withdraw")
- )
- return menu
- #Функция для получения ТОЛЬКО подтвержденных номеров
- def get_confirmed_numbers():
- connection = sqlite3.connect('your_database.db')
- cursor = connection.cursor()
- try:
- cursor.execute("SELECT number, time FROM confirmed_numbers")
- confirmed_numbers = cursor.fetchall()
- logging.info(f"📂 Данные из базы: {confirmed_numbers}") # Логируем, что возвращает БД
- return confirmed_numbers
- except Exception as e:
- logging.error(f"❌ Ошибка при запросе данных: {e}")
- return []
- finally:
- connection.close()
- conn = sqlite3.connect("bot_database.db")
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM confirmed_numbers")
- numbers = cursor.fetchall()
- if numbers:
- print("✅ Подтвержденные номера:", numbers)
- else:
- print("⚠️ В таблице confirmed_numbers нет данных!")
- conn.close()
- # Функция для создания таблицы, если ее еще нет
- def create_table():
- connection = sqlite3.connect('your_database.db') # Путь к базе данных
- cursor = connection.cursor()
- # Запрос для создания таблицы
- cursor.execute('''
- CREATE TABLE IF NOT EXISTS confirmed_numbers (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- number TEXT NOT NULL,
- time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- );
- ''')
- connection.commit() # Применяем изменения
- connection.close() # Закрываем соединение
- # Вызов функции для создания таблицы
- create_table()
- # Функция для добавления номера в базу данных
- def add_number_to_db(number):
- connection = sqlite3.connect('your_database.db') # Указывай путь к своей базе данных
- cursor = connection.cursor()
- # Проверка на существование номера в базе данных (если нужно)
- cursor.execute("SELECT COUNT(*) FROM confirmed_numbers WHERE number = ?", (number,))
- if cursor.fetchone()[0] > 0:
- return False # Номер уже существует в базе данных
- # Добавление номера в базу данных
- cursor.execute("INSERT INTO confirmed_numbers (number) VALUES (?)", (number,))
- connection.commit()
- connection.close()
- return True
- def add_number_to_db(number):
- connection = sqlite3.connect('your_database.db')
- cursor = connection.cursor()
- # Проверяем, есть ли номер в базе
- cursor.execute("SELECT COUNT(*) FROM confirmed_numbers WHERE number = ?", (number,))
- if cursor.fetchone()[0] > 0:
- logging.info(f"Номер {number} уже есть в базе.")
- return False # Номер уже существует
- # Добавляем номер
- cursor.execute("INSERT INTO confirmed_numbers (number) VALUES (?)", (number,))
- connection.commit()
- logging.info(f"✅ Номер {number} добавлен в базу.")
- connection.close()
- return True
- @dp.callback_query_handler(lambda c: c.data == "admin_list")
- async def admin_list(call: types.CallbackQuery):
- confirmed_numbers = get_confirmed_numbers() # Получаем подтвержденные номера
- logging.info(f"Полученные данные о номерах: {confirmed_numbers}") # Логируем результат
- # Проверка, что данные получены корректно
- if not confirmed_numbers or not isinstance(confirmed_numbers, list):
- await call.message.answer("⚠️ Ошибка: Не удалось загрузить подтвержденные номера.")
- await call.answer()
- return
- if len(confirmed_numbers) == 0:
- await call.message.answer("⚠️ Подтвержденных номеров нет.")
- await call.answer()
- return
- # Формируем список номеров
- try:
- list_text = "📜 **Список подтвержденных номеров:**\n\n"
- list_text += "\n".join([f"📞 {num[0]} - 🕒 {num[1]}" for num in confirmed_numbers])
- except (IndexError, TypeError):
- await call.message.answer("⚠️ Ошибка: Неверный формат данных о номерах.")
- await call.answer()
- return
- # Отправляем список
- await call.message.answer(list_text, parse_mode="Markdown")
- await call.answer()
- @dp.message_handler(commands=['admin'])
- async def admin_menu(message: types.Message):
- if message.from_user.id not in ADMIN_USER_IDS:
- return await message.answer("❌ У вас нет доступа к админ-панели.")
- markup = InlineKeyboardMarkup().add(
- InlineKeyboardButton("📋 Список номеров", callback_data="admin_list"),
- InlineKeyboardButton("💰 Засчитать баланс", callback_data="admin_add_balance")
- )
- await message.answer("🔧 Админ-панель:", reply_markup=markup)
- @dp.callback_query_handler(lambda c: c.data == "admin_add_balance")
- async def admin_add_balance_prompt(call: types.CallbackQuery):
- await call.message.answer("Введите номер и сумму через пробел (пример: 1234567890 10)")
- await BalanceInput.waiting_for_number_and_amount.set()
- # Обработчик для ввода номера и суммы
- @dp.message_handler(state=BalanceInput.waiting_for_number_and_amount)
- async def process_balance_input(message: types.Message, state: FSMContext):
- text = message.text.strip()
- # Регулярное выражение для номера и суммы
- match = re.match(r"^(\+?\d{10,15})\s+(\d+)$", text)
- if not match:
- await message.reply("❌ Ошибка: некорректный формат. Введите номер и сумму через пробел.\nПример: `1234567890 10`", parse_mode="Markdown")
- return
- phone_number, amount = match.groups()
- amount = float(amount)
- # Создаем клавиатуру с кнопкой "Назад"
- back_button = InlineKeyboardMarkup()
- back_button.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
- try:
- if phone_number not in user_numbers:
- await message.reply("❌ Ошибка: номер не найден.")
- return
- user_id = user_numbers[phone_number]["user_id"]
- user_balances[user_id] = user_balances.get(user_id, 0.0) + amount
- # Отправляем сообщение пользователю с кнопкой "Назад"
- await bot.send_message(user_id, f"✅ Вам начислено {amount:.2f} USD.", reply_markup=back_button)
- # Отправляем сообщение обратно в чат с кнопкой "Назад"
- await message.answer(f"✅ Пользователю {user_id} начислено {amount:.2f} USD.", reply_markup=back_button)
- except KeyError:
- await message.reply("❌ Ошибка: проблема с базой данных номеров.")
- except ValueError:
- await message.reply("❌ Ошибка: некорректная сумма.")
- finally:
- await state.finish()
- # Функция для добавления пользователя в базу данных
- def add_user(user_id, username, referral_code=None, referred_by=None):
- conn = sqlite3.connect("users.db")
- cursor = conn.cursor()
- cursor.execute("INSERT INTO users (user_id, username, referral_code, referred_by) VALUES (?, ?, ?, ?)",
- (user_id, username, referral_code, referred_by))
- conn.commit()
- conn.close()
- # Функция для получения информации о пользователе
- def get_user(user_id):
- conn = sqlite3.connect("users.db")
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
- user = cursor.fetchone()
- conn.close()
- return user
- # Функция для обновления баланса пользователя
- def update_balance(user_id, amount):
- conn = sqlite3.connect("users.db")
- cursor = conn.cursor()
- cursor.execute("UPDATE users SET balance = balance + ? WHERE user_id = ?", (amount, user_id))
- conn.commit()
- conn.close()
- # Главная кнопка меню с реферальной ссылкой
- @dp.callback_query_handler(lambda c: c.data == "referral_link")
- async def referral_link(call: types.CallbackQuery):
- user_id = call.from_user.id
- user = get_user(user_id)
- if not user:
- # Если пользователь еще не зарегистрирован в базе, то добавляем его
- referral_code = generate_referral_code()
- add_user(user_id, call.from_user.username, referral_code)
- referral_url = f"t.me/{BOT_USERNAME}?start={user[2]}" # Пример реферальной ссылки
- await call.message.answer(f"Ваша реферальная ссылка: {referral_url}")
- await call.answer()
- from datetime import datetime
- import sqlite3
- @dp.callback_query_handler(lambda c: c.data.startswith("code_entered_") or c.data.startswith("code_not_entered_"))
- async def handle_code_confirmation(callback_query: types.CallbackQuery):
- number = callback_query.data.split("_")[-1]
- user_id = user_numbers.get(number, {}).get("user_id")
- if not user_id:
- return await callback_query.answer("Ошибка: номер не найден!")
- now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- if callback_query.data.startswith("code_entered_"):
- save_confirmed_number(number, now)
- text = f"✅ Номер {number} подтверждён в {now}!"
- else:
- save_rejected_number(number, now)
- text = f"❌ Номер {number} отклонён в {now}!"
- save_user(user_id)
- # Отправка сообщения в админ-чат с кнопками
- admin_keyboard = InlineKeyboardMarkup().row(
- InlineKeyboardButton("📩 Взять номер", callback_data=f"take_{number}"),
- InlineKeyboardButton("⏭ Пропустить номер", callback_data=f"skip_{number}")
- )
- await bot.send_message(ADMIN_GROUP_ID, text, reply_markup=admin_keyboard)
- await callback_query.answer("✅ Данные сохранены и статистика обновлена!")
- # === 🔥 Запуск бота ===
- if __name__ == "__main__":
- logging.basicConfig(level=logging.INFO)
- executor.start_polling(dp, skip_updates=False)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement