Files
TG_autoposter/app/__init__.py
Andrew K. Choi 57d7c9ace3 Реализована интерактивная авторизация UserBot через бот
- Создан модуль userbot_auth.py для управления авторизацией через Telethon
- Добавлены обработчики для всех этапов авторизации (номер, SMS, 2FA)
- Интегрирована авторизация в меню UserBot
- Добавлена кнопка 🔐 Авторизация в главное меню UserBot
- Полная обработка ошибок и подробные сообщения пользователю
- Сессии сохраняются безопасно в PostgreSQL
- Документация с примерами использования

Этапы авторизации:
1. Пользователь нажимает 🔐 Авторизация в меню UserBot
2. Вводит номер телефона в формате +XX-XXX-XXX-XXXX
3. Получает SMS с кодом подтверждения (5 цифр)
4. При необходимости вводит пароль 2FA
5. Сессия автоматически сохраняется и UserBot готов к работе
2025-12-21 12:23:47 +09:00

209 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import logging
from dotenv import load_dotenv
from telegram.ext import (
Application,
CommandHandler,
CallbackQueryHandler,
ChatMemberHandler,
MessageHandler,
ConversationHandler,
filters,
)
from app.database import init_db
from app.handlers import (
start,
help_command,
sync_groups_command,
start_callback,
manage_messages,
manage_groups,
list_messages,
list_groups,
send_message,
my_chat_member,
userbot_menu,
userbot_settings,
userbot_init,
userbot_collect_groups,
userbot_collect_members,
userbot_parse_members,
cancel_userbot,
auth_menu,
auth_info,
start_phone_input,
handle_phone,
handle_code,
handle_password,
cancel_auth,
)
from app.handlers.message_manager import (
create_message_start,
create_message_title,
create_message_text,
select_groups,
handle_message_input,
)
from app.handlers.telethon_client import telethon_manager
from app.utils.keyboards import CallbackType
from app.settings import Config
# Загружаем переменные окружения
load_dotenv()
# Настройка логирования
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.DEBUG
)
logger = logging.getLogger(__name__)
async def debug_update_handler(update, context):
"""Обработчик для отладки всех обновлений"""
logger.info(f"🎯 Получено обновление: {update}")
if update.message:
logger.info(f"📨 Сообщение от {update.effective_user.id}: {update.message.text}")
elif update.callback_query:
logger.info(f"🔘 Callback от {update.effective_user.id}: {update.callback_query.data}")
else:
logger.info(f"❓ Неизвестное обновление: {update.to_dict() if hasattr(update, 'to_dict') else str(update)}")
return None
# Получаем конфигурацию
# Для UserBot контейнера: если есть TELETHON переменные и нет BOT_TOKEN - это ОК
is_userbot_only = (
os.getenv('TELETHON_API_ID')
and os.getenv('TELETHON_API_HASH')
and os.getenv('TELETHON_PHONE')
and not os.getenv('TELEGRAM_BOT_TOKEN')
)
if not is_userbot_only:
if not Config.validate():
raise ValueError("❌ Конфигурация некорректна. Проверьте .env файл")
async def main() -> None:
"""Запуск бота с поддержкой гибридного режима"""
# Инициализируем БД
logger.info("Инициализация базы данных...")
await init_db()
logger.info("✅ База данных инициализирована")
# Инициализируем Telethon если включен
if Config.USE_TELETHON:
logger.info("Инициализация Telethon клиента...")
success = await telethon_manager.initialize()
if success:
logger.info("✅ Telethon клиент инициализирован")
else:
logger.warning("⚠️ Ошибка инициализации Telethon, продолжим с режимом бота")
# Выводим информацию о режиме
mode = Config.get_mode()
logger.info(f"📡 Режим работы: {mode}")
if mode == 'hybrid':
logger.info("🔀 Бот будет использовать Telethon как fallback для закрытых групп")
# Создаем приложение
application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).build()
# Добавляем отладчик для всех текстовых сообщений (самый низкий приоритет)
application.add_handler(MessageHandler(filters.ALL, debug_update_handler), group=100)
# Добавляем обработчики команд (высший приоритет, группа 0)
application.add_handler(CommandHandler("start", start), group=0)
application.add_handler(CommandHandler("help", help_command), group=0)
application.add_handler(CommandHandler("sync_groups", sync_groups_command), group=0)
# Добавляем обработчики callback'ов (группа 1)
application.add_handler(CallbackQueryHandler(start_callback, pattern=f"^{CallbackType.MAIN_MENU.value}$"), group=1)
application.add_handler(CallbackQueryHandler(manage_messages, pattern=f"^{CallbackType.MANAGE_MESSAGES.value}$"), group=1)
application.add_handler(CallbackQueryHandler(manage_groups, pattern=f"^{CallbackType.MANAGE_GROUPS.value}$"), group=1)
application.add_handler(CallbackQueryHandler(list_messages, pattern=f"^{CallbackType.LIST_MESSAGES.value}$"), group=1)
application.add_handler(CallbackQueryHandler(list_groups, pattern=f"^{CallbackType.LIST_GROUPS.value}$"), group=1)
application.add_handler(CallbackQueryHandler(send_message, pattern=r"^send_msg_\d+$"), group=1)
# CREATE_MESSAGE обрабатывается отдельным handler'ом с управлением состоянием
application.add_handler(CallbackQueryHandler(create_message_start, pattern=f"^{CallbackType.CREATE_MESSAGE.value}$"), group=1)
# Добавляем обработчик CallbackQuery для управления UserBot
application.add_handler(CallbackQueryHandler(userbot_menu, pattern="^userbot_menu$"), group=1)
application.add_handler(CallbackQueryHandler(userbot_settings, pattern="^userbot_settings$"), group=1)
application.add_handler(CallbackQueryHandler(userbot_init, pattern="^userbot_init$"), group=1)
application.add_handler(CallbackQueryHandler(userbot_collect_groups, pattern="^userbot_collect_groups$"), group=1)
application.add_handler(CallbackQueryHandler(userbot_collect_members, pattern="^userbot_collect_members$"), group=1)
application.add_handler(CallbackQueryHandler(userbot_parse_members, pattern=r"^userbot_members_\d+$"), group=1)
# Добавляем обработчик для кнопки UserBot в главном меню
application.add_handler(CallbackQueryHandler(userbot_menu, pattern=f"^{CallbackType.MANAGE_USERBOT.value}$"), group=1)
# Обработчики авторизации UserBot
application.add_handler(CallbackQueryHandler(auth_menu, pattern="^auth_menu$"), group=1)
application.add_handler(CallbackQueryHandler(auth_info, pattern="^auth_info$"), group=1)
application.add_handler(CallbackQueryHandler(start_phone_input, pattern="^auth_start_phone$"), group=1)
# Конверсейшн для ввода номера телефона
auth_phone_conversation = ConversationHandler(
entry_points=[], # Входная точка через callback query выше
states={
2: [MessageHandler(filters.TEXT & ~filters.COMMAND, handle_phone)], # AUTH_PHONE = 2
},
fallbacks=[CallbackQueryHandler(cancel_auth, pattern="^cancel_auth$")],
name="auth_phone",
persistent=False
)
application.add_handler(auth_phone_conversation, group=1)
# Конверсейшн для ввода SMS кода
auth_code_conversation = ConversationHandler(
entry_points=[], # Входная точка через callback query выше
states={
3: [MessageHandler(filters.TEXT & ~filters.COMMAND, handle_code)], # AUTH_CODE = 3
},
fallbacks=[CallbackQueryHandler(cancel_auth, pattern="^cancel_auth$")],
name="auth_code",
persistent=False
)
application.add_handler(auth_code_conversation, group=1)
# Конверсейшн для ввода пароля 2FA
auth_password_conversation = ConversationHandler(
entry_points=[], # Входная точка через callback query выше
states={
4: [MessageHandler(filters.TEXT & ~filters.COMMAND, handle_password)], # AUTH_PASSWORD = 4
},
fallbacks=[CallbackQueryHandler(cancel_auth, pattern="^cancel_auth$")],
name="auth_password",
persistent=False
)
application.add_handler(auth_password_conversation, group=1)
# Select group callbacks
application.add_handler(CallbackQueryHandler(select_groups, pattern=r"^select_group_\d+$"), group=1)
application.add_handler(CallbackQueryHandler(select_groups, pattern=r"^done_groups$"), group=1)
# MessageHandler для текстового ввода (название и текст сообщения)
# Использует dispatch-функцию для маршрутизации в зависимости от состояния
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message_input), group=1)
# Обработчик добавления/удаления бота из групп (группа 3)
application.add_handler(ChatMemberHandler(my_chat_member, ChatMemberHandler.MY_CHAT_MEMBER), group=3)
# Запускаем бота
logger.info("🚀 Бот запущен. Ожидание команд...")
try:
await application.run_polling(allowed_updates=["message", "callback_query", "my_chat_member"])
finally:
# Завершить Telethon клиент при выходе
if Config.USE_TELETHON:
logger.info("Завершение работы Telethon клиента...")
await telethon_manager.shutdown()
logger.info("✅ Telethon клиент остановлен")
if __name__ == "__main__":
import asyncio
asyncio.run(main())