""" Обработчики команд /start и /help """ from datetime import datetime from aiogram import Router, F from aiogram.types import Message from aiogram.filters import Command, CommandStart from aiogram.fsm.context import FSMContext from config import config from models.user import User from services.infrastructure.database import DatabaseService from services.auth.auth_new import AuthService from services.utils import UtilsService from services.business.user_service import UserService from services.business.message_service import MessageService from services.infrastructure.logger import get_logger from services.infrastructure.metrics import get_metrics_service, track_message_processing from keyboards.reply import get_main_keyboard_for_user, get_admin_reply_keyboard from keyboards.inline import get_admin_keyboard from dependencies import inject_start_services, inject_link_services, inject_main_menu_services logger = get_logger(__name__) router = Router() async def _create_welcome_message(user: User, referral_link: str) -> str: """Создание приветственного сообщения""" welcome_text = f"👋 Добро пожаловать, {user.display_name}!\n\n" welcome_text += "🤖 Я бот для анонимных вопросов.\n\n" welcome_text += "📝 Как это работает:\n" welcome_text += "• Поделитесь своей ссылкой с друзьями\n" welcome_text += "• Они смогут задать вам анонимные вопросы\n" welcome_text += "• Вы получите уведомления и сможете ответить\n\n" welcome_text += f"🔗 Ваша персональная ссылка:\n" welcome_text += f"{referral_link}\n\n" welcome_text += "💡 Совет: Скопируйте ссылку и поделитесь ею в социальных сетях!" return welcome_text async def _process_start_command( message: Message, user_service: UserService, auth: AuthService, utils: UtilsService, message_service: MessageService, validator ) -> User: """Обработка команды /start без аргументов""" # Валидируем Telegram ID пользователя user_id_validation = validator.validate_telegram_id(message.from_user.id) if not user_id_validation: logger.error(f"❌ Невалидный Telegram ID: {message.from_user.id}") await message_service.send_message( message, "❌ Ошибка: недопустимый ID пользователя.", get_main_keyboard_for_user(message.from_user.id) ) raise ValueError(f"Invalid Telegram ID: {message.from_user.id}") # Создаем или обновляем пользователя user = await user_service.create_or_update_user(message.from_user, message.chat.id) # Проверяем, является ли пользователь админом is_admin = auth.is_admin(user.telegram_id) # Генерируем персональную ссылку bot_info = await message.bot.get_me() referral_link = user_service.generate_referral_link(bot_info.username, user) # Создаем приветственное сообщение welcome_text = await _create_welcome_message(user, referral_link) # Выбираем клавиатуру в зависимости от роли if is_admin: keyboard = get_admin_reply_keyboard() else: keyboard = get_main_keyboard_for_user(user.telegram_id) logger.info(f"⌨️ Создана клавиатура для пользователя {user.telegram_id}: {type(keyboard).__name__}") # Отправляем сообщение await message_service.send_message(message, welcome_text, keyboard) logger.info(f"✅ Приветственное сообщение отправлено пользователю {user.telegram_id}") return user @router.message(CommandStart()) @track_message_processing("start_command") @inject_start_services async def cmd_start( message: Message, state: FSMContext, user_service: UserService, auth: AuthService, utils: UtilsService, message_service: MessageService, validator, **kwargs ): """Обработчик команды /start""" try: logger.info(f"🚀 Команда /start от пользователя {message.from_user.id} ({message.from_user.first_name})") # Сбрасываем состояние FSM при команде /start await state.clear() logger.info(f"🔄 Состояние FSM сброшено для пользователя {message.from_user.id}") # Получаем аргументы команды args = message.text.split()[1:] if len(message.text.split()) > 1 else [] # Обрабатываем deep linking если есть аргументы if args: logger.info(f"🔗 Обработка deep link: {args[0]}") await handle_deep_link(message, args[0], user_service, state, message_service, validator) else: # Обрабатываем обычную команду /start await _process_start_command(message, user_service, auth, utils, message_service, validator) except Exception as e: logger.error(f"💥 Ошибка в обработчике /start: {e}") await message_service.send_error_message( message, "❌ Произошла ошибка при запуске бота. Попробуйте позже." ) async def handle_deep_link( message: Message, ref_code: str, user_service: UserService, state: FSMContext, message_service: MessageService, validator ): """Обработка deep linking для анонимных вопросов""" try: # Валидируем deep link validation_result = validator.validate_deep_link(ref_code) if not validation_result: logger.warning(f"⚠️ Невалидный deep link от пользователя {message.from_user.id}: {ref_code}") await message_service.send_message( message, f"❌ {validation_result.error_message}", get_main_keyboard_for_user(message.from_user.id) ) return # Используем санитизированное значение ref_code = validation_result.sanitized_value if not ref_code.startswith('ref_'): await message_service.send_message( message, "❌ Неверная ссылка.", get_main_keyboard_for_user(message.from_user.id) ) return # Извлекаем анонимный ID из реферального кода anonymous_id = ref_code[4:] # Убираем 'ref_' # Ищем пользователя по profile_link target_user = await user_service.get_user_by_profile_link(anonymous_id) if not target_user: await message_service.send_message( message, "❌ Пользователь, на которого вы перешли, не найден.", get_main_keyboard_for_user(message.from_user.id) ) return # Отправляем сообщение о переходе по ссылке deep_link_text = ( f"👋 Вы перешли по ссылке пользователя {target_user.display_name}!\n\n" f"📝 Теперь вы можете задать анонимный вопрос.\n" f"Просто отправьте ваше сообщение, и оно будет передано получателю." ) await message_service.send_message( message, deep_link_text, get_main_keyboard_for_user(message.from_user.id) ) # Устанавливаем состояние ожидания вопроса from aiogram.fsm.state import State, StatesGroup class QuestionStates(StatesGroup): waiting_for_question = State() await state.set_state(QuestionStates.waiting_for_question) await state.update_data(target_user_id=target_user.telegram_id) except Exception as e: logger.error(f"Ошибка при обработке deep link: {e}") await message_service.send_error_message( message, "❌ Произошла ошибка при обработке ссылки." ) @router.message(Command("help")) async def cmd_help(message: Message): """Обработчик команды /help""" help_text = "📖 Справка по боту\n\n" help_text += "🤖 Основные команды:\n" help_text += "/start - Запуск бота и получение персональной ссылки\n" help_text += "/help - Показать эту справку\n" help_text += "/stats - Показать статистику (только для админов)\n\n" help_text += "📝 Как задать анонимный вопрос:\n" help_text += "1. Перейдите по персональной ссылке пользователя\n" help_text += "2. Отправьте ваш вопрос боту\n" help_text += "3. Вопрос будет передан получателю анонимно\n\n" help_text += "💬 Как ответить на вопрос:\n" help_text += "1. Получите уведомление о новом вопросе\n" help_text += "2. Нажмите кнопку 'Ответить'\n" help_text += "3. Введите ваш ответ\n" help_text += "4. Ответ будет отправлен анонимно\n\n" help_text += "🔗 Ваша персональная ссылка:\n" help_text += "Используйте кнопку 'Моя ссылка' для получения ссылки\n\n" help_text += "❓ Нужна помощь?\n" help_text += "Обратитесь к администратору бота: @Kerrad1" await message.answer(help_text, parse_mode="HTML") @router.message(F.text == "ℹ️ Помощь") async def help_button(message: Message): """Обработчик кнопки 'Помощь'""" await cmd_help(message) @router.message(F.text == "🔗 Моя ссылка") @inject_link_services async def my_link_button( message: Message, user_service: UserService, message_service: MessageService, **kwargs ): """Обработчик кнопки 'Моя ссылка'""" try: # Получаем пользователя из БД user = await user_service.get_user_by_telegram_id(message.from_user.id) if not user: await message_service.send_message( message, "❌ Пользователь не найден. Используйте /start для регистрации." ) return # Получаем информацию о боте bot_info = await message.bot.get_me() referral_link = user_service.generate_referral_link(bot_info.username, user) link_text = "🔗 Ваша персональная ссылка:\n\n" link_text += f"{referral_link}\n\n" link_text += "📝 Как использовать:\n" link_text += "• Скопируйте ссылку\n" link_text += "• Поделитесь ею в социальных сетях\n" link_text += "• Друзья смогут задать вам анонимные вопросы\n\n" link_text += "💡 Совет: Добавьте ссылку в описание профиля или поделитесь в Stories!" await message_service.send_message(message, link_text) except Exception as e: logger.error(f"Ошибка при получении ссылки: {e}") await message_service.send_error_message( message, "❌ Произошла ошибка при получении ссылки. Попробуйте позже." ) @router.message(F.text == "⬅️ Главное меню") @inject_main_menu_services async def back_to_main( message: Message, state: FSMContext, auth: AuthService, message_service: MessageService, **kwargs ): """Обработчик кнопки 'Главное меню'""" # Сбрасываем состояние FSM при возврате в главное меню await state.clear() logger.info(f"🔄 Состояние FSM сброшено для пользователя {message.from_user.id} (кнопка 'Главное меню')") is_admin = auth.is_admin(message.from_user.id) if is_admin: keyboard = get_admin_reply_keyboard() else: keyboard = get_main_keyboard_for_user(message.from_user.id) await message_service.send_message( message, "🏠 Главное меню\n\nВыберите действие:", keyboard ) @router.message(F.text == "⚙️ Админ панель") @inject_main_menu_services async def admin_panel_button( message: Message, auth: AuthService, message_service: MessageService, **kwargs ): """Обработчик кнопки 'Админ панель'""" # Проверяем, является ли пользователь админом if not auth.is_admin(message.from_user.id): await message_service.send_message( message, "❌ У вас нет прав для доступа к админ панели." ) return # Получаем inline клавиатуру для админов admin_keyboard = get_admin_keyboard() await message_service.send_message( message, "👑 Админ панель\n\nВыберите действие:", admin_keyboard )