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
226 lines
11 KiB
Python
226 lines
11 KiB
Python
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)}"
|
||
)
|