Files
TG_autoposter/app/handlers/commands.py
Andrew K. Choi 48f8c6f0eb 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
2025-12-21 12:09:11 +09:00

226 lines
11 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

from telegram import Update
from telegram.ext import ContextTypes
from app.database import AsyncSessionLocal
from app.database.repository import GroupRepository, MessageRepository, MessageGroupRepository
from app.utils.keyboards import get_main_keyboard, get_groups_keyboard, get_messages_keyboard
from app.handlers.telethon_client import telethon_manager
from app.userbot.parser import userbot_parser
import logging
logger = logging.getLogger(__name__)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Обработчик команды /start"""
user = update.effective_user
logger.info(f"📧 Получена команда /start от пользователя {user.id} (@{user.username})")
text = f"""👋 Привет, {user.first_name}!
Я бот для автоматической рассылки сообщений в группы.
Что я умею:
• 📨 Создавать и управлять сообщениями
• 👥 Добавлять группы и управлять ими
• 📤 Отправлять сообщения со скоростью группы (slow mode)
• 📊 Отслеживать статус отправки
Выберите действие:"""
await update.message.reply_text(
text,
reply_markup=get_main_keyboard()
)
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Обработчик команды /help"""
user = update.effective_user
logger.info(f"📧 Получена команда /help от пользователя {user.id}")
text = """📖 Справка по использованию:
<b>Основные команды:</b>
/start - Главное меню
/help - Эта справка
<b>Как работать с сообщениями:</b>
1. Перейдите в раздел "Сообщения"
2. Создайте новое сообщение
3. Введите текст сообщения
4. Выберите группы для отправки
<b>Как работать с группами:</b>
1. Бот автоматически обнаружит группы при добавлении
2. Для каждой группы можно настроить slow mode
3. Вы сможете отправлять разные сообщения в разные группы
<b>Slow mode:</b>
Это ограничение на скорость отправки сообщений в группу.
Бот автоматически учитывает это при отправке.
Нажмите /start для возврата в главное меню."""
await update.message.reply_text(text, parse_mode='HTML')
async def _sync_groups_with_userbot(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Синхронизировать группы через новый UserBot парсер"""
try:
status_message = await update.message.reply_text(
"⏳ Синхронизирую группы через UserBot парсер..."
)
# Используем userbot для парсинга участников существующих групп
async with AsyncSessionLocal() as session:
repo = GroupRepository(session)
existing_groups = await repo.get_all_active_groups()
if not existing_groups:
await status_message.edit_text(
" В БД нет групп для синхронизации участников.\n\n"
"Сначала добавьте группы через /start → Группы"
)
return
synced_count = 0
for group in existing_groups:
try:
# Синхронизировать информацию о группе и участников
success = await userbot_parser.sync_group_to_db(int(group.chat_id))
if success:
synced_count += 1
logger.info(f"✅ Синхронизирована группа: {group.title}")
except Exception as e:
logger.error(f"❌ Ошибка при синхронизации {group.title}: {e}")
await session.commit()
result_text = f"""✅ <b>Синхронизация завершена!</b>
📊 Результаты:
• 🔄 Синхронизировано: {synced_count} групп
Информация о участниках обновлена и сохранена в БД!"""
await status_message.edit_text(result_text, parse_mode='HTML')
logger.info(f"✅ Синхронизация участников завершена: {synced_count} групп")
except Exception as e:
logger.error(f"❌ Ошибка при синхронизации через UserBot: {e}", exc_info=True)
await update.message.reply_text(
f"❌ Ошибка при синхронизации: {str(e)}"
)
async def sync_groups_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Синхронизировать группы из Telethon UserBot или UserBot парсера"""
user = update.effective_user
logger.info(f"🔄 Получена команда /sync_groups от пользователя {user.id}")
# Попытаться инициализировать userbot если еще не инициализирован
if not userbot_parser.is_initialized:
logger.info("📱 Инициализация UserBot парсера...")
init_success = await userbot_parser.initialize()
if not init_success:
logger.warning("⚠️ UserBot парсер не инициализирован, используем старый telethon_manager")
# Попытаться использовать новый userbot сначала
if userbot_parser.is_initialized:
logger.info("✅ Используем новый UserBot парсер")
return await _sync_groups_with_userbot(update, context)
else:
logger.info(" Используем старый Telethon клиент")
return await _sync_groups_with_telethon(update, context)
async def _sync_groups_with_telethon(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Синхронизировать группы через telethon_manager"""
user = update.effective_user
logger.info(f"🔄 Синхронизация через telethon_manager")
# Проверим, инициализирован ли Telethon клиент
if not telethon_manager.is_connected():
logger.warning("⚠️ Telethon клиент не инициализирован")
await update.message.reply_text(
"❌ Telethon UserBot не инициализирован.\n\n"
"Убедитесь, что переменные окружения TELETHON_API_ID и TELETHON_API_HASH установлены."
)
return
try:
# Отправим уведомление о начале синхронизации
status_message = await update.message.reply_text(
"⏳ Синхронизирую группы через Telethon UserBot..."
)
# Получить все группы от Telethon
groups = await telethon_manager.get_user_groups()
if not groups:
await status_message.edit_text(
" UserBot не найден ни в одной группе.\n\n"
"Чтобы добавить группы:\n"
"1. Пригласите UserBot в групп\u044b\n"
"2. Повторите /sync_groups"
)
return
# Сохранить группы в БД
added_count = 0
updated_count = 0
async with AsyncSessionLocal() as session:
repo = GroupRepository(session)
for group in groups:
try:
# Конвертировать chat_id в string
chat_id_str = str(group['chat_id'])
# Попытаться найти существующую группу
existing = await repo.get_group_by_chat_id(chat_id_str)
if existing:
# Обновить информацию
await repo.update_group(
existing.id,
title=group['title'],
slow_mode_delay=group['slow_mode_delay']
)
updated_count += 1
logger.info(f"✏️ Обновлена группа: {group['title']} (ID: {chat_id_str})")
else:
# Добавить новую группу
await repo.add_group(
chat_id=chat_id_str,
title=group['title'],
slow_mode_delay=group['slow_mode_delay']
)
added_count += 1
logger.info(f"✅ Добавлена группа: {group['title']} (ID: {chat_id_str})")
except Exception as e:
logger.error(f"❌ Ошибка при добавлении группы {group['title']}: {e}")
continue
await session.commit()
# Отправить результаты
result_text = f"""✅ <b>Синхронизация завершена!</b>
📊 Результаты:
Добавлено: {added_count}
• ✏️ Обновлено: {updated_count}
• 📈 Всего в БД: {added_count + updated_count}
Теперь вы можете использовать эти группы для отправки сообщений!"""
await status_message.edit_text(result_text, parse_mode='HTML')
logger.info(f"✅ Синхронизация завершена: добавлено {added_count}, обновлено {updated_count}")
except Exception as e:
logger.error(f"❌ Ошибка при синхронизации групп: {e}", exc_info=True)
await update.message.reply_text(
f"❌ Ошибка при синхронизации: {str(e)}"
)