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

@@ -1,5 +1,5 @@
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import ContextTypes, ConversationHandler
from telegram.ext import ContextTypes
from app.database import AsyncSessionLocal
from app.database.repository import GroupRepository, MessageRepository, MessageGroupRepository
from app.utils.keyboards import (
@@ -10,16 +10,11 @@ import logging
logger = logging.getLogger(__name__)
# Состояния для ConversationHandler
WAITING_MESSAGE_TEXT = 1
WAITING_MESSAGE_TITLE = 2
WAITING_GROUP_SELECTION = 3
WAITING_FOR_GROUP = 4
async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Главное меню"""
query = update.callback_query
logger.info(f"🔘 Получена кнопка MAIN_MENU от пользователя {update.effective_user.id}")
await query.answer()
text = """🤖 <b>Автопостер - Главное меню</b>
@@ -35,50 +30,61 @@ async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
async def manage_messages(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Меню управления сообщениями"""
query = update.callback_query
await query.answer()
text = """📨 <b>Управление сообщениями</b>
try:
query = update.callback_query
logger.info(f"🔘 Получена кнопка MANAGE_MESSAGES от пользователя {update.effective_user.id}")
await query.answer()
text = """📨 <b>Управление сообщениями</b>
Выберите действие:"""
keyboard = [
[InlineKeyboardButton(" Новое сообщение", callback_data=CallbackType.CREATE_MESSAGE)],
[InlineKeyboardButton("📜 Список сообщений", callback_data=CallbackType.LIST_MESSAGES)],
[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MAIN_MENU)],
]
keyboard = [
[InlineKeyboardButton(" Новое сообщение", callback_data=CallbackType.CREATE_MESSAGE.value)],
[InlineKeyboardButton("📜 Список сообщений", callback_data=CallbackType.LIST_MESSAGES.value)],
[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MAIN_MENU.value)],
]
await query.edit_message_text(
text,
parse_mode='HTML',
reply_markup=InlineKeyboardMarkup(keyboard)
)
await query.edit_message_text(
text,
parse_mode='HTML',
reply_markup=InlineKeyboardMarkup(keyboard)
)
logger.info(f"✅ Сообщение обновлено для manage_messages")
except Exception as e:
logger.error(f"❌ Ошибка в manage_messages: {e}", exc_info=True)
async def manage_groups(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Меню управления группами"""
query = update.callback_query
await query.answer()
text = """👥 <b>Управление группами</b>
try:
query = update.callback_query
logger.info(f"🔘 Получена кнопка MANAGE_GROUPS от пользователя {update.effective_user.id}")
await query.answer()
text = """👥 <b>Управление группами</b>
Выберите действие:"""
keyboard = [
[InlineKeyboardButton("📜 Список групп", callback_data=CallbackType.LIST_GROUPS)],
[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MAIN_MENU)],
]
keyboard = [
[InlineKeyboardButton("📜 Список групп", callback_data=CallbackType.LIST_GROUPS.value)],
[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MAIN_MENU.value)],
]
await query.edit_message_text(
text,
parse_mode='HTML',
reply_markup=InlineKeyboardMarkup(keyboard)
)
await query.edit_message_text(
text,
parse_mode='HTML',
reply_markup=InlineKeyboardMarkup(keyboard)
)
logger.info(f"✅ Сообщение обновлено для manage_groups")
except Exception as e:
logger.error(f"❌ Ошибка в manage_groups: {e}", exc_info=True)
async def list_messages(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Список всех сообщений"""
query = update.callback_query
logger.info(f"🔘 Получена кнопка LIST_MESSAGES от пользователя {update.effective_user.id}")
await query.answer()
async with AsyncSessionLocal() as session:
@@ -87,7 +93,7 @@ async def list_messages(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
if not messages:
text = "📭 Нет сообщений"
keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_MESSAGES)]]
keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_MESSAGES.value)]]
else:
text = "📨 <b>Ваши сообщения:</b>\n\n"
keyboard = []
@@ -100,7 +106,7 @@ async def list_messages(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
InlineKeyboardButton("🗑️", callback_data=f"delete_msg_{msg.id}")
])
keyboard.append([InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_MESSAGES)])
keyboard.append([InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_MESSAGES.value)])
await query.edit_message_text(
text,
@@ -112,6 +118,7 @@ async def list_messages(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
async def list_groups(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Список всех групп"""
query = update.callback_query
logger.info(f"🔘 Получена кнопка LIST_GROUPS от пользователя {update.effective_user.id}")
await query.answer()
async with AsyncSessionLocal() as session:
@@ -120,7 +127,7 @@ async def list_groups(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
if not groups:
text = "👥 Нет групп в базе данных\n\nДобавьте бота в группы - они автоматически появятся здесь."
keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_GROUPS)]]
keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_GROUPS.value)]]
else:
text = "👥 <b>Группы в базе данных:</b>\n\n"
keyboard = []
@@ -137,7 +144,7 @@ async def list_groups(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
InlineKeyboardButton("🗑️", callback_data=f"delete_group_{group.id}")
])
keyboard.append([InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_GROUPS)])
keyboard.append([InlineKeyboardButton("⬅️ Назад", callback_data=CallbackType.MANAGE_GROUPS.value)])
await query.edit_message_text(
text,