from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton from telegram.ext import ContextTypes from app.database import AsyncSessionLocal from app.database.repository import ( GroupRepository, MessageRepository, MessageGroupRepository ) from app.utils.keyboards import ( get_back_keyboard, get_main_keyboard, CallbackType ) import logging logger = logging.getLogger(__name__) # Состояния (теперь управляются через context.user_data) STATE_WAITING_MSG_TITLE = "waiting_title" STATE_WAITING_MSG_TEXT = "waiting_text" STATE_SELECTING_GROUPS = "selecting_groups" async def handle_message_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Распределяет текстовый ввод в зависимости от текущего состояния""" state = context.user_data.get('message_state') if state == STATE_WAITING_MSG_TITLE: await create_message_title(update, context) elif state == STATE_WAITING_MSG_TEXT: await create_message_text(update, context) # Если не в состоянии ввода - игнорируем async def create_message_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Начало создания нового сообщения""" query = update.callback_query logger.info(f"📝 Начало создания сообщения от пользователя {update.effective_user.id}") await query.answer() # Инициализируем состояние context.user_data['message_state'] = STATE_WAITING_MSG_TITLE context.user_data['message_title'] = None context.user_data['message_text'] = None context.user_data['selected_groups'] = set() text = "📝 Введите название сообщения (короткое описание):" await query.edit_message_text(text) async def create_message_title(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Получаем название и просим текст""" message = update.message # Проверяем что мы в правильном состоянии if context.user_data.get('message_state') != STATE_WAITING_MSG_TITLE: return logger.info(f"📝 Получено название сообщения: {message.text[:50]}") title = message.text.strip() if len(title) > 100: await message.reply_text("❌ Название слишком длинное (макс 100 символов)") return context.user_data['message_title'] = title context.user_data['message_state'] = STATE_WAITING_MSG_TEXT text = """✏️ Теперь введите текст сообщения. Вы можете использовать HTML форматирование: жирный курсив подчеркивание код Введите /cancel для отмены""" await message.reply_text(text, parse_mode='HTML') async def create_message_text(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Получаем текст и показываем выбор групп""" message = update.message # Проверяем что мы в правильном состоянии if context.user_data.get('message_state') != STATE_WAITING_MSG_TEXT: return logger.info(f"📝 Получен текст сообщения от пользователя {update.effective_user.id}") if message.text == '/cancel': context.user_data['message_state'] = None await message.reply_text("❌ Отменено", reply_markup=get_main_keyboard()) return text = message.text.strip() if len(text) > 4096: await message.reply_text("❌ Текст слишком длинный (макс 4096 символов)") return context.user_data['message_text'] = text # Сохраняем сообщение в БД async with AsyncSessionLocal() as session: msg_repo = MessageRepository(session) msg = await msg_repo.add_message( text=text, title=context.user_data['message_title'] ) context.user_data['message_id'] = msg.id # Теперь показываем список групп для выбора async with AsyncSessionLocal() as session: group_repo = GroupRepository(session) groups = await group_repo.get_all_active_groups() if not groups: context.user_data['message_state'] = None await message.reply_text( "❌ Нет активных групп. Сначала добавьте бота в группы.", reply_markup=get_main_keyboard() ) return # Создаем клавиатуру с группами keyboard = [] for group in groups: callback = f"select_group_{group.id}" keyboard.append([InlineKeyboardButton( f"☐ {group.title} (delay: {group.slow_mode_delay}s)", callback_data=callback )]) keyboard.append([InlineKeyboardButton("✔️ Готово", callback_data="done_groups")]) keyboard.append([InlineKeyboardButton("❌ Отмена", callback_data=CallbackType.MAIN_MENU.value)]) text = f"""✅ Сообщение создано: {context.user_data['message_title']} Выберите группы для отправки (нажмите на каждую):""" await message.reply_text( text, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(keyboard) ) context.user_data['selected_groups'] = set() context.user_data['message_state'] = STATE_SELECTING_GROUPS async def select_groups(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Выбор групп для отправки""" query = update.callback_query callback_data = query.data # Проверяем что мы в правильном состоянии if context.user_data.get('message_state') != STATE_SELECTING_GROUPS: return logger.info(f"🔘 Получен callback select_groups: {callback_data} от пользователя {update.effective_user.id}") await query.answer() if callback_data == "done_groups": # Подтверждаем выбор selected = context.user_data.get('selected_groups', set()) if not selected: await query.answer("❌ Выберите хотя бы одну группу", show_alert=True) return # Добавляем сообщение в выбранные группы message_id = context.user_data['message_id'] async with AsyncSessionLocal() as session: mg_repo = MessageGroupRepository(session) for group_id in selected: await mg_repo.add_message_to_group(message_id, group_id) text = f"""✅ Сообщение готово! Название: {context.user_data['message_title']} Групп выбрано: {len(selected)} Теперь вы можете отправить сообщение нажав кнопку "Отправить" в списке сообщений.""" context.user_data['message_state'] = None await query.edit_message_text(text, parse_mode='HTML', reply_markup=get_main_keyboard()) return elif callback_data.startswith("select_group_"): group_id = int(callback_data.split("_")[2]) selected = context.user_data.get('selected_groups', set()) if group_id in selected: selected.discard(group_id) else: selected.add(group_id) context.user_data['selected_groups'] = selected # Обновляем клавиатуру async with AsyncSessionLocal() as session: group_repo = GroupRepository(session) groups = await group_repo.get_all_active_groups() keyboard = [] for group in groups: callback = f"select_group_{group.id}" is_selected = group.id in selected prefix = "✅" if is_selected else "☐" keyboard.append([InlineKeyboardButton( f"{prefix} {group.title} (delay: {group.slow_mode_delay}s)", callback_data=callback )]) keyboard.append([InlineKeyboardButton("✔️ Готово", callback_data="done_groups")]) keyboard.append([InlineKeyboardButton("❌ Отмена", callback_data=CallbackType.MAIN_MENU.value)]) await query.edit_message_text( f"Выбрано групп: {len(selected)}", reply_markup=InlineKeyboardMarkup(keyboard) ) await query.answer() return SELECT_GROUPS elif callback_data == CallbackType.MAIN_MENU: # Отмена await query.answer() await query.edit_message_text( "❌ Создание сообщения отменено", reply_markup=get_main_keyboard() ) return ConversationHandler.END await query.answer() return SELECT_GROUPS