from typing import List, Optional from fastapi import APIRouter, HTTPException, Depends from pydantic import BaseModel from app.services import DatabaseManager from instance.configdb import get_database_manager from uuid import UUID import logging from sqlalchemy.exc import SQLAlchemyError logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) router = APIRouter() class BuySubscriptionRequest(BaseModel): telegram_id: int plan_name: str class SubscriptionResponse(BaseModel): id: str user_id: int plan_name: str vpn_server_id: Optional[str] status: str start_date: str end_date: str created_at: str # Эндпоинт для покупки подписки @router.post("/subscription/buy", response_model=dict) async def buy_subscription( request_data: BuySubscriptionRequest, database_manager: DatabaseManager = Depends(get_database_manager) ): """ Покупка подписки. """ try: logger.info(f"Получен запрос на покупку подписки: {request_data.dict()}") result = await database_manager.buy_sub(request_data.telegram_id, request_data.plan_name) logger.info(f"Результат buy_sub: {result}") if result == "ERROR": raise HTTPException(status_code=500, detail="Internal server error") elif result == "INSUFFICIENT_FUNDS": raise HTTPException(status_code=400, detail="INSUFFICIENT_FUNDS") elif result == "TARIFF_NOT_FOUND": raise HTTPException(status_code=400, detail="TARIFF_NOT_FOUND") elif result == "ACTIVE_SUBSCRIPTION_EXISTS": raise HTTPException(status_code=400, detail="ACTIVE_SUBSCRIPTION_EXISTS") elif result == "USER_NOT_FOUND": raise HTTPException(status_code=404, detail="USER_NOT_FOUND") elif result == "SUBSCRIPTION_CREATION_FAILED": raise HTTPException(status_code=500, detail="Failed to create subscription") elif result == "PAYMENT_FAILED_AFTER_SUBSCRIPTION": raise HTTPException(status_code=402, detail="SUBSCRIPTION_CREATED_BUT_PAYMENT_FAILED") elif result == "SUBSCRIPTION_CREATED_BUT_PAYMENT_FAILED": raise HTTPException(status_code=402, detail="SUBSCRIPTION_CREATED_BUT_PAYMENT_FAILED") # Если успешно, генерируем URI if isinstance(result, dict) and result.get('status') == 'OK': uri_result = await database_manager.generate_uri(request_data.telegram_id) logger.info(f"Результат генерации URI: {uri_result}") return { "status": "success", "subscription_id": result.get('subscription_id'), "uri": uri_result[0] if uri_result and isinstance(uri_result, list) else uri_result } else: return {"status": "success", "message": "Subscription created"} except HTTPException as http_exc: logger.error(f"HTTPException в buy_subscription: {http_exc.detail}") raise http_exc except Exception as e: logger.error(f"Неожиданная ошибка в buy_subscription: {str(e)}") raise HTTPException(status_code=500, detail=f"Unexpected error: {str(e)}") # Эндпоинт для получения последней подписки @router.get("/subscription/{telegram_id}/last", response_model=SubscriptionResponse) async def last_subscription(telegram_id: int, database_manager: DatabaseManager = Depends(get_database_manager)): """ Возвращает последнюю подписку пользователя. """ logger.info(f"Получение последней подписки для пользователя: {telegram_id}") try: subscription = await database_manager.get_last_subscriptions(telegram_id=telegram_id) if not subscription : logger.warning(f"Подписки для пользователя {telegram_id} не найдены") raise HTTPException(status_code=404, detail="No subscriptions found") plan = await database_manager.get_plan_by_id(subscription.plan_id) if not plan: logger.warning(f"Тариф для пользователя {telegram_id} не найдены") raise HTTPException(status_code=404, detail="No plan found") return { "id": str(subscription.id), "user_id": subscription.user_id, "plan_name": plan.name, "vpn_server_id": subscription.vpn_server_id, "status": subscription.status.value, "start_date": subscription.start_date.isoformat(), "end_date": subscription.end_date.isoformat(), "created_at": subscription.created_at.isoformat(), } except SQLAlchemyError as e: logger.error(f"Ошибка базы данных при получении подписки для пользователя {telegram_id}: {e}") raise HTTPException(status_code=500, detail="Database error") except HTTPException as e: # Пропускаем HTTPException, чтобы FastAPI обработал её автоматически raise e except Exception as e: logger.error(f"Неожиданная ошибка: {e}") raise HTTPException(status_code=500, detail="Internal Server Error") @router.get("/subscriptions/{telegram_id}", response_model=List[SubscriptionResponse]) async def get_subscriptions(telegram_id: int, database_manager: DatabaseManager = Depends(get_database_manager)): """ Возвращает список подписок пользователя. """ logger.info(f"Получение подписок для пользователя: {telegram_id}") try: # Получаем подписки без ограничений или с указанным лимитом subscription = await database_manager.get_last_subscriptions(telegram_id=telegram_id) if not subscription: logger.warning(f"Подписки для пользователя {telegram_id} не найдены") raise HTTPException(status_code=404, detail="No subscriptions found") plan = await database_manager.get_plan_by_id(subscription.plan_id) if not plan: logger.warning(f"Тариф для подписки {subscription.id} не найден") plan_name = "Unknown" else: plan_name = plan.name # Формируем список подписок для ответа # return [ # { # "id": sub.id, # "plan": sub.plan, # "vpn_server_id": sub.vpn_server_id, # "expiry_date": sub.expiry_date.isoformat(), # "created_at": sub.created_at.isoformat(), # "updated_at": sub.updated_at.isoformat(), # } # for sub in subscription # ] return [{ "id": str(subscription.id), # Конвертируем UUID в строку "user_id": subscription.user_id, "plan_name": plan_name, "vpn_server_id": subscription.vpn_server_id, "end_date": subscription.end_date.isoformat(), "status": subscription.status.value, # Извлекаем значение enum "start_date": subscription.start_date.isoformat(), "created_at": subscription.created_at.isoformat() }] except SQLAlchemyError as e: logger.error(f"Ошибка базы данных при получении подписок для пользователя {telegram_id}: {e}") raise HTTPException(status_code=500, detail="Database error") except Exception as e: logger.error(f"Неожиданная ошибка: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.get("/uri", response_model=dict) async def get_uri(telegram_id: int, database_manager: DatabaseManager = Depends(get_database_manager)): """ Возвращает список подписок пользователя. """ logger.info(f"Получение подписок для пользователя: {telegram_id}") try: # Получаем подписки без ограничений или с указанным лимитом uri = await database_manager.generate_uri(telegram_id) if uri == "SUB_ERROR": raise HTTPException(status_code=404, detail="SUB_ERROR") if not uri: logger.warning(f"Не удалось сгенерировать URI для пользователя с telegram_id {telegram_id}, данные -> {uri}") raise HTTPException(status_code=404, detail="URI not found") return {"detail": uri[0]} except HTTPException as e: # Пропускаем HTTPException, чтобы FastAPI обработал её автоматически raise e except SQLAlchemyError as e: logger.error(f"Ошибка базы данных при получении подписок для пользователя {telegram_id}: {e}") raise HTTPException(status_code=500, detail="Database error") except Exception as e: logger.error(f"Неожиданная ошибка: {e}") raise HTTPException(status_code=500, detail=str(e))