mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-11 22:50:30 +00:00
140 lines
4.3 KiB
Python
140 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Iterable, Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Security, status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.database.models import Subscription, SubscriptionEvent, Transaction, User
|
|
from app.database.crud.subscription_event import (
|
|
create_subscription_event,
|
|
list_subscription_events,
|
|
)
|
|
from ..dependencies import get_db_session, require_api_token
|
|
from ..schemas.subscription_events import (
|
|
SubscriptionEventCreate,
|
|
SubscriptionEventListResponse,
|
|
SubscriptionEventResponse,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
async def _get_user_or_error(db: AsyncSession, user_id: int) -> User:
|
|
user = await db.get(User, user_id)
|
|
if not user:
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
|
return user
|
|
|
|
|
|
async def _ensure_subscription_exists(
|
|
db: AsyncSession, subscription_id: Optional[int]
|
|
) -> None:
|
|
if not subscription_id:
|
|
return
|
|
|
|
subscription = await db.get(Subscription, subscription_id)
|
|
if not subscription:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Subscription not found",
|
|
)
|
|
|
|
|
|
async def _ensure_transaction_exists(db: AsyncSession, transaction_id: Optional[int]) -> None:
|
|
if not transaction_id:
|
|
return
|
|
|
|
transaction_exists = await db.scalar(
|
|
select(Transaction.id).where(Transaction.id == transaction_id)
|
|
)
|
|
if not transaction_exists:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Transaction not found",
|
|
)
|
|
|
|
|
|
def _serialize_event(event: SubscriptionEvent) -> SubscriptionEventResponse:
|
|
user = event.user
|
|
|
|
extra = event.extra or {}
|
|
|
|
if event.event_type == "promocode_activation":
|
|
extra = {**extra}
|
|
extra.setdefault("balance_before_kopeks", None)
|
|
extra.setdefault("balance_after_kopeks", None)
|
|
|
|
return SubscriptionEventResponse(
|
|
id=event.id,
|
|
event_type=event.event_type,
|
|
user_id=event.user_id,
|
|
user_full_name=user.full_name if user else "",
|
|
user_username=user.username if user else None,
|
|
user_telegram_id=user.telegram_id if user else 0,
|
|
subscription_id=event.subscription_id,
|
|
transaction_id=event.transaction_id,
|
|
amount_kopeks=event.amount_kopeks,
|
|
currency=event.currency,
|
|
message=event.message,
|
|
occurred_at=event.occurred_at,
|
|
created_at=event.created_at,
|
|
extra=extra,
|
|
)
|
|
|
|
|
|
@router.post("", response_model=SubscriptionEventResponse, status_code=status.HTTP_201_CREATED)
|
|
async def receive_subscription_event(
|
|
payload: SubscriptionEventCreate,
|
|
_: Any = Security(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
) -> SubscriptionEventResponse:
|
|
user = await _get_user_or_error(db, payload.user_id)
|
|
await _ensure_subscription_exists(db, payload.subscription_id)
|
|
await _ensure_transaction_exists(db, payload.transaction_id)
|
|
|
|
event = await create_subscription_event(
|
|
db,
|
|
user_id=payload.user_id,
|
|
event_type=payload.event_type,
|
|
subscription_id=payload.subscription_id,
|
|
transaction_id=payload.transaction_id,
|
|
amount_kopeks=payload.amount_kopeks,
|
|
currency=payload.currency,
|
|
message=payload.message,
|
|
occurred_at=payload.occurred_at,
|
|
extra=payload.extra or None,
|
|
)
|
|
|
|
await db.refresh(event, attribute_names=["user"])
|
|
|
|
event.user = user
|
|
|
|
return _serialize_event(event)
|
|
|
|
|
|
@router.get("", response_model=SubscriptionEventListResponse)
|
|
async def list_subscription_event_logs(
|
|
_: Any = Security(require_api_token),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
limit: int = Query(50, ge=1, le=200),
|
|
offset: int = Query(0, ge=0),
|
|
event_types: Optional[Iterable[str]] = Query(default=None, alias="event_type"),
|
|
user_id: Optional[int] = Query(default=None),
|
|
) -> SubscriptionEventListResponse:
|
|
events, total = await list_subscription_events(
|
|
db,
|
|
limit=limit,
|
|
offset=offset,
|
|
event_types=event_types,
|
|
user_id=user_id,
|
|
)
|
|
|
|
return SubscriptionEventListResponse(
|
|
items=[_serialize_event(event) for event in events],
|
|
total=total,
|
|
limit=limit,
|
|
offset=offset,
|
|
)
|