UserBot Integration Complete: Fixed container startup, integrated UserBot menu to main bot

MAJOR FIXES:
 Fixed UserBot container startup by making TELEGRAM_BOT_TOKEN optional
 Broke circular import chain between app modules
 Made Config.validate() conditional for UserBot-only mode
 Removed unused celery import from userbot_service.py

INTEGRATION:
 UserBot menu now accessible from main bot /start command
 Added 🤖 UserBot button to main keyboard
 Integrated userbot_manager.py handlers:
   - userbot_menu: Main UserBot interface
   - userbot_settings: Configuration
   - userbot_collect_groups: Gather all user groups
   - userbot_collect_members: Parse group members
 UserBot handlers properly registered in ConversationHandler

CONTAINERS:
 tg_autoposter_bot: Running and handling /start commands
 tg_autoposter_userbot: Running as standalone microservice
 All dependent services (Redis, PostgreSQL, Celery workers) operational

STATUS: Bot is fully operational and ready for testing
This commit is contained in:
2025-12-21 12:09:11 +09:00
parent b8136138dc
commit 48f8c6f0eb
48 changed files with 6593 additions and 113 deletions

View File

@@ -6,14 +6,15 @@ from telegram.ext import (
CommandHandler,
CallbackQueryHandler,
ChatMemberHandler,
ConversationHandler,
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,
@@ -21,33 +22,60 @@ from app.handlers import (
list_groups,
send_message,
my_chat_member,
userbot_menu,
userbot_settings,
userbot_init,
userbot_collect_groups,
userbot_collect_members,
userbot_parse_members,
cancel_userbot,
)
from app.handlers.message_manager import (
create_message_start,
create_message_title,
create_message_text,
select_groups,
CREATE_MSG_TITLE,
CREATE_MSG_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.INFO
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
# Получаем конфигурацию
if not Config.validate():
raise ValueError("❌ Конфигурация некорректна. Проверьте .env файл")
# Для 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:
@@ -76,34 +104,44 @@ async def main() -> None:
# Создаем приложение
application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).build()
# Добавляем обработчики команд
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
# Добавляем отладчик для всех текстовых сообщений (самый низкий приоритет)
application.add_handler(MessageHandler(filters.ALL, debug_update_handler), group=100)
# ConversationHandler для создания сообщения
create_message_handler = ConversationHandler(
entry_points=[CallbackQueryHandler(create_message_start, pattern=f"^{CallbackType.CREATE_MESSAGE}$")],
states={
CREATE_MSG_TITLE: [MessageHandler(filters.TEXT & ~filters.COMMAND, create_message_title)],
CREATE_MSG_TEXT: [MessageHandler(filters.TEXT & ~filters.COMMAND, create_message_text)],
SELECT_GROUPS: [CallbackQueryHandler(select_groups, pattern=r"^(select_group_\d+|done_groups|main_menu)$")],
},
fallbacks=[CommandHandler("cancel", start)],
)
application.add_handler(create_message_handler)
# Добавляем обработчики команд (высший приоритет, группа 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'ов
application.add_handler(CallbackQueryHandler(start_callback, pattern=f"^{CallbackType.MAIN_MENU}$"))
application.add_handler(CallbackQueryHandler(manage_messages, pattern=f"^{CallbackType.MANAGE_MESSAGES}$"))
application.add_handler(CallbackQueryHandler(manage_groups, pattern=f"^{CallbackType.MANAGE_GROUPS}$"))
application.add_handler(CallbackQueryHandler(list_messages, pattern=f"^{CallbackType.LIST_MESSAGES}$"))
application.add_handler(CallbackQueryHandler(list_groups, pattern=f"^{CallbackType.LIST_GROUPS}$"))
# Добавляем обработчики 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)
# Отправка сообщений
application.add_handler(CallbackQueryHandler(send_message, pattern=r"^send_msg_\d+$"))
# Добавляем обработчик для кнопки UserBot в главном меню
application.add_handler(CallbackQueryHandler(userbot_menu, pattern=f"^{CallbackType.MANAGE_USERBOT.value}$"), group=1)
# Обработчик добавления/удаления бота из групп
application.add_handler(ChatMemberHandler(my_chat_member, ChatMemberHandler.MY_CHAT_MEMBER))
# 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("🚀 Бот запущен. Ожидание команд...")