from aiogram import Router, types from aiogram.filters import Command from aiogram.types import Message, CallbackQuery from aiogram.enums.parse_mode import ParseMode import logging import aiohttp from instences.config import BASE_URL_FASTAPI from keyboard.keyboards import main_keyboard from .referrals import _build_referral_text router = Router() logger = logging.getLogger(__name__) async def call_api(method: str, endpoint: str, data=None): """ Выполняет HTTP-запрос к FastAPI. Возвращает: - dict при 200/201 - None при 404 - "ERROR" при остальных ошибках """ url = f"{BASE_URL_FASTAPI}{endpoint}" logger.info(f"[start] Запрос: {method} {url} с данными {data}") try: async with aiohttp.ClientSession() as session: async with session.request(method, url, json=data) as response: logger.info( f"[start] Ответ от {url}: статус {response.status}" ) if response.status in {200, 201}: result = await response.json() logger.debug(f"[start] Ответ JSON: {result}") return result if response.status == 404: logger.debug("[start] Получен 404, возвращаю None") return None logger.error( f"[start] Ошибка в запросе: статус {response.status}, " f"причина {response.reason}" ) return "ERROR" except Exception as e: logger.exception(f"[start] Исключение при запросе к {url}: {e}") return "ERROR" def _welcome_text(username: str | None) -> str: """ Текст приветствия в /start и в главном меню. """ return "🥚 Lark Security\n\nВыберите действие из меню ниже." def _parse_referrer_id(message: Message) -> int | None: """ Достаём ref_ из /start. Примеры: /start /start ref_123456789 """ text = message.text or "" parts = text.split(maxsplit=1) if len(parts) < 2: return None arg = parts[1].strip() if not arg.startswith("ref_"): return None raw_id = arg[4:] if not raw_id.isdigit(): return None try: return int(raw_id) except ValueError: return None @router.message(Command("start")) async def start_command(message: Message): """ /start c обработкой реферального параметра. """ user_id = message.from_user.id username = message.from_user.username referrer_id = _parse_referrer_id(message) logger.info( f"[start] Команда /start от {user_id} (@{username}), " f"text={message.text!r}, referrer_id={referrer_id}" ) try: # 1. Проверяем, есть ли пользователь в БД existing = await call_api("GET", f"/user/{user_id}") user_exists = existing not in (None, "ERROR") # 2. Если пользователя нет — создаём if not user_exists: logger.debug(f"[start] Пользователь {user_id} не найден, создаю.") create_result = await call_api( "POST", "/user/create", {"telegram_id": user_id}, ) if create_result == "ERROR": logger.error( f"[start] Не удалось создать пользователя {user_id} в БД" ) # 3. Обработка рефералки, если параметр есть if referrer_id is not None: # 3.1. Самореферал if referrer_id == user_id: logger.info( f"[start] Пользователь {user_id} попытался зайти " f"по своей реферальной ссылке." ) await message.answer( "Нельзя переходить по своей же реферальной ссылке." ) # 3.2. Пользователь уже зарегистрирован в боте elif user_exists: logger.info( f"[start] Пользователь {user_id} уже есть в БД, " f"реферальная ссылка {referrer_id} не сработает." ) await message.answer( "Вы уже зарегистрированы в боте, " "реферальная ссылка не сработает." ) # 3.3. Новый пользователь + чужая рефералка → регистрируем реферал else: payload = { "referrer_id": referrer_id, "telegram_id": user_id, } logger.info( f"[start] Фиксирую реферала в бекенде: {payload}" ) result = await call_api( "POST", "/user/referrals/track", payload, ) if result == "ERROR": logger.error( f"[start] Ошибка при фиксации реферала: {payload}" ) await message.answer( "Вы вошли по реферальной ссылке." ) # 4. В любом случае показываем главное меню await message.answer( _welcome_text(username), reply_markup=main_keyboard(), ) logger.info(f"[start] Главное меню отправлено пользователю {user_id}.") except Exception as e: logger.exception( f"[start] Ошибка при обработке /start для пользователя {user_id}: {e}" ) await message.answer("Произошла ошибка. Попробуйте позже.") @router.message(Command("referrals")) async def referrals_menu_command(message: Message): """ Команда /referrals из бокового меню Telegram. Показывает текст реферальной программы. """ logger.info( f"[start] Команда /referrals от {message.from_user.id} " f"(@{message.from_user.username})" ) try: text = await _build_referral_text(message.bot, message.from_user.id) await message.answer(text, parse_mode=ParseMode.HTML) logger.info("[start] Реферальная программа отправлена пользователю.") except Exception as e: logger.exception( f"[start] Ошибка при обработке /referrals для пользователя " f"{message.from_user.id}: {e}" ) await message.answer("Произошла ошибка. Попробуйте позже.") @router.callback_query(lambda callback: callback.data == "base") async def start_callback_handler(callback: CallbackQuery): """ Callback с data="base" — возврат в главное меню. """ try: user_id = callback.from_user.id username = callback.from_user.username logger.info(f"[start] callback 'base' от {user_id} (@{username})") user_data = await call_api("GET", f"/user/{user_id}") if user_data in (None, "ERROR"): await call_api( "POST", "/user/create", {"telegram_id": user_id}, ) await callback.message.edit_text( _welcome_text(username), reply_markup=main_keyboard(), ) except Exception as e: logger.exception(f"[start] Ошибка при обработке callback 'base': {e}") await callback.message.answer("Произошла ошибка. Попробуйте позже.") finally: await callback.answer()