""" Обработчик управления UserBot для сбора групп и участников """ from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton from telegram.ext import ContextTypes, ConversationHandler from app.userbot.parser import userbot_parser from app.database import AsyncSessionLocal from app.database.repository import GroupRepository from app.database.member_repository import GroupMemberRepository from app.utils.keyboards import CallbackType from app.handlers.userbot_auth import ( auth_menu, auth_info, start_phone_input, handle_phone, handle_code, handle_password, cancel_auth, AUTH_START, AUTH_PHONE, AUTH_CODE, AUTH_PASSWORD, ) import logging import os logger = logging.getLogger(__name__) # Состояния для ConversationHandler USERBOT_MENU = 1 USERBOT_SETTINGS = 2 USERBOT_COLLECTING_GROUPS = 3 USERBOT_SELECT_GROUP = 4 USERBOT_COLLECTING_MEMBERS = 5 async def userbot_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Меню управления UserBot""" try: query = update.callback_query if query: await query.answer() text = """🤖 UserBot - Управление парсингом Что вы хотите сделать? UserBot собирает информацию о группах и их участниках от имени пользователя""" keyboard = [ [InlineKeyboardButton("🔐 Авторизация", callback_data="auth_menu")], [InlineKeyboardButton("⚙️ Настройки", callback_data="userbot_settings")], [InlineKeyboardButton("📥 Собрать группы", callback_data="userbot_collect_groups")], [InlineKeyboardButton("👥 Собрать участников", callback_data="userbot_collect_members")], [InlineKeyboardButton("⬅️ Назад в меню", callback_data=CallbackType.MAIN_MENU.value)], ] if query: await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) else: await update.message.reply_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_MENU except Exception as e: logger.error(f"❌ Ошибка в userbot_menu: {e}", exc_info=True) return ConversationHandler.END async def userbot_settings(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Настройки UserBot""" try: query = update.callback_query await query.answer() # Проверяем статус UserBot is_initialized = userbot_parser.is_initialized status = "✅ Инициализирован" if is_initialized else "❌ Не инициализирован" text = f"""⚙️ Настройки UserBot Статус: {status} Возможности: • Собирать информацию о группах • Собирать списки участников • Сохранять данные в БД • Работать в фоне через Celery Нажмите кнопку для продолжения""" keyboard = [ [InlineKeyboardButton("🔄 Инициализировать", callback_data="userbot_init")], [InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")], ] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_SETTINGS except Exception as e: logger.error(f"❌ Ошибка в userbot_settings: {e}", exc_info=True) return ConversationHandler.END async def userbot_init(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Инициализация UserBot""" try: query = update.callback_query await query.answer() await query.edit_message_text( "⏳ Инициализирую UserBot...", parse_mode='HTML' ) # Инициализируем UserBot success = await userbot_parser.initialize() if success: text = """✅ UserBot успешно инициализирован! Теперь вы можете: • Собирать информацию о группах • Собирать списки участников • Синхронизировать данные в БД Перейдите в меню для продолжения.""" keyboard = [[InlineKeyboardButton("🔄 Меню", callback_data="userbot_menu")]] else: text = """❌ Ошибка инициализации UserBot Убедитесь, что: • Переменные окружения установлены • TELETHON_API_ID и TELETHON_API_HASH верные • Сессия сохранена в sessions/userbot_session.session Попробуйте позже.""" keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_settings")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_SETTINGS except Exception as e: logger.error(f"❌ Ошибка инициализации UserBot: {e}", exc_info=True) text = f"""❌ Ошибка при инициализации: {str(e)[:200]} Проверьте логи бота.""" keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_settings")]] query = update.callback_query await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_SETTINGS async def userbot_collect_groups(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Сбор групп от пользователя""" try: query = update.callback_query await query.answer() if not userbot_parser.is_initialized: text = "❌ UserBot не инициализирован!\n\nПерейдите в настройки для инициализации." keyboard = [[InlineKeyboardButton("⚙️ Настройки", callback_data="userbot_settings")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_MENU await query.edit_message_text( "⏳ Собираю информацию о группах...\n\nЭто может занять некоторое время...", parse_mode='HTML' ) # Собираем группы logger.info(f"📥 Начало сбора групп для пользователя {update.effective_user.id}") groups = await userbot_parser.parse_groups_user_in() if not groups: text = "❌ Не найдено групп\n\nУбедитесь, что вы состоите в группах." keyboard = [[InlineKeyboardButton("🔄 Попробовать снова", callback_data="userbot_collect_groups")], [InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")]] else: # Сохраняем группы в контексте context.user_data['available_groups'] = groups text = f"""✅ Найдено групп: {len(groups)} Список групп:""" for i, group in enumerate(groups, 1): title = group.get('title', 'Неизвестная группа') chat_id = group.get('chat_id', 'Unknown') members = group.get('members_count', 0) text += f"\n{i}. {title}\n 👥 Участников: {members}" text += "\n\n💾 Группы сохранены в базе данных!" # Сохраняем группы в БД async with AsyncSessionLocal() as session: repo = GroupRepository(session) for group in groups: await repo.add_or_update_group({ 'chat_id': group.get('chat_id'), 'title': group.get('title'), 'description': group.get('description', ''), 'members_count': group.get('members_count', 0), 'is_active': True }) logger.info(f"✅ Сохранено {len(groups)} групп") keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_COLLECTING_GROUPS except Exception as e: logger.error(f"❌ Ошибка при сборе групп: {e}", exc_info=True) text = f"""❌ Ошибка при сборе групп: {str(e)[:200]}""" keyboard = [[InlineKeyboardButton("🔄 Попробовать снова", callback_data="userbot_collect_groups")], [InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")]] query = update.callback_query await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_COLLECTING_GROUPS async def userbot_collect_members(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Выбор группы для сбора участников""" try: query = update.callback_query await query.answer() if not userbot_parser.is_initialized: text = "❌ UserBot не инициализирован!\n\nПерейдите в настройки для инициализации." keyboard = [[InlineKeyboardButton("⚙️ Настройки", callback_data="userbot_settings")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_MENU # Получаем группы из БД async with AsyncSessionLocal() as session: repo = GroupRepository(session) groups = await repo.get_active_groups() if not groups: text = "❌ Не найдено активных групп\n\nСначала соберите информацию о группах." keyboard = [[InlineKeyboardButton("📥 Собрать группы", callback_data="userbot_collect_groups")], [InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_SELECT_GROUP text = """👥 Выберите группу для сбора участников Нажмите на группу для сбора списка участников:""" keyboard = [] for group in groups: title = group.title if hasattr(group, 'title') else group.get('title', 'Unknown') group_id = group.id if hasattr(group, 'id') else group.get('id', 0) callback_data = f"userbot_members_{group_id}" keyboard.append([InlineKeyboardButton(f"👥 {title}", callback_data=callback_data)]) keyboard.append([InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")]) await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_SELECT_GROUP except Exception as e: logger.error(f"❌ Ошибка при выборе группы: {e}", exc_info=True) text = f"""❌ Ошибка: {str(e)[:200]}""" keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_menu")]] query = update.callback_query await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_SELECT_GROUP async def userbot_parse_members(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Сбор участников для выбранной группы""" try: query = update.callback_query await query.answer() # Извлекаем group_id из callback_data group_id = int(query.data.replace("userbot_members_", "")) await query.edit_message_text( f"⏳ Собираю участников группы...\n\ngroup_id: {group_id}\n\nЭто может занять некоторое время...", parse_mode='HTML' ) # Получаем информацию о группе из БД async with AsyncSessionLocal() as session: repo = GroupRepository(session) group = await repo.get_group_by_id(group_id) if not group: text = "❌ Группа не найдена в базе данных." keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_collect_members")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_COLLECTING_MEMBERS chat_id = group.chat_id if hasattr(group, 'chat_id') else group.get('chat_id') title = group.title if hasattr(group, 'title') else group.get('title', 'Unknown') logger.info(f"👥 Начало сбора участников для группы {title} (chat_id: {chat_id})") # Собираем участников members = await userbot_parser.parse_group_members(chat_id=chat_id, limit=10000) if not members: text = f"❌ Не удалось собрать участников группы:\n{title}" keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_collect_members")]] else: # Сохраняем участников в БД async with AsyncSessionLocal() as session: member_repo = GroupMemberRepository(session) for member in members: await member_repo.add_or_update_member({ 'group_id': group_id, 'user_id': member.get('user_id'), 'username': member.get('username'), 'first_name': member.get('first_name'), 'last_name': member.get('last_name'), 'is_bot': member.get('is_bot', False), 'is_admin': member.get('is_admin', False), 'is_owner': member.get('is_owner', False), }) # Статистика total = len(members) bots = len([m for m in members if m.get('is_bot')]) admins = len([m for m in members if m.get('is_admin')]) owners = len([m for m in members if m.get('is_owner')]) text = f"""✅ Участники собраны! Группа: {title} Статистика: • 👥 Всего участников: {total} • 🤖 Ботов: {bots} • 👑 Администраторов: {admins} • 🔑 Владельцев: {owners} 💾 Данные сохранены в базе данных!""" logger.info(f"✅ Сохранено {total} участников группы {title}") keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_collect_members")]] await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_COLLECTING_MEMBERS except Exception as e: logger.error(f"❌ Ошибка при сборе участников: {e}", exc_info=True) text = f"""❌ Ошибка при сборе участников: {str(e)[:200]} Это может быть вызвано: • FloodWait от Telegram • Недостатком прав доступа • Проблемой с сессией UserBot""" keyboard = [[InlineKeyboardButton("⬅️ Назад", callback_data="userbot_collect_members")], [InlineKeyboardButton("🏠 Меню", callback_data="userbot_menu")]] query = update.callback_query await query.edit_message_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return USERBOT_COLLECTING_MEMBERS # Экспорт функций авторизации для использования в других модулях __all__ = [ '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', ] async def cancel_userbot(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Отмена диалога""" query = update.callback_query if query: await query.answer() keyboard = [[InlineKeyboardButton("🏠 Главное меню", callback_data=CallbackType.MAIN_MENU.value)]] await query.edit_message_text( "❌ Диалог отменен", parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) return ConversationHandler.END