- FastAPI REST API with JWT auth - aiogram 3 Telegram bot with admin middleware - APScheduler daily tasks (expiry, reminders, revoke, sync) - SQLAlchemy 2 async ORM with Alembic migrations - Jinja2 admin panel (Dashboard, Users, Payments, Servers, Tariffs) - VPN provider abstraction with MockProvider - Stats service with revenue/subscription analytics - Docker Compose (PostgreSQL + Redis + app) - Healthcheck endpoint
84 lines
2.5 KiB
Python
84 lines
2.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
|
|
from app.api.deps import (
|
|
get_user_service,
|
|
get_billing_service,
|
|
)
|
|
from app.schemas.user import UserRead, UserUpdate
|
|
from app.services import UserService, BillingService
|
|
|
|
router = APIRouter(prefix="/users", tags=["Users"])
|
|
|
|
|
|
@router.get("/{user_id}", response_model=UserRead)
|
|
async def get_user(
|
|
user_id: int,
|
|
user_svc: UserService = Depends(get_user_service),
|
|
):
|
|
user = await user_svc.get_by_id(user_id)
|
|
if user is None:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return user
|
|
|
|
|
|
@router.patch("/{user_id}", response_model=UserRead)
|
|
async def update_user(
|
|
user_id: int,
|
|
body: UserUpdate,
|
|
user_svc: UserService = Depends(get_user_service),
|
|
):
|
|
user = await user_svc.update(user_id, **body.model_dump(exclude_unset=True))
|
|
if user is None:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return user
|
|
|
|
|
|
@router.post("/{user_id}/deactivate", response_model=UserRead)
|
|
async def deactivate_user(
|
|
user_id: int,
|
|
user_svc: UserService = Depends(get_user_service),
|
|
):
|
|
ok = await user_svc.deactivate(user_id)
|
|
if not ok:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return await user_svc.get_by_id(user_id)
|
|
|
|
|
|
@router.post("/{user_id}/activate", response_model=UserRead)
|
|
async def activate_user(
|
|
user_id: int,
|
|
user_svc: UserService = Depends(get_user_service),
|
|
):
|
|
ok = await user_svc.activate(user_id)
|
|
if not ok:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return await user_svc.get_by_id(user_id)
|
|
|
|
|
|
@router.get("/by-telegram/{telegram_id}", response_model=UserRead)
|
|
async def get_user_by_telegram(
|
|
telegram_id: int,
|
|
user_svc: UserService = Depends(get_user_service),
|
|
):
|
|
user = await user_svc.get_by_telegram_id(telegram_id)
|
|
if user is None:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return user
|
|
|
|
|
|
@router.get("/{user_id}/subscription")
|
|
async def get_user_subscription(
|
|
user_id: int,
|
|
billing_svc: BillingService = Depends(get_billing_service),
|
|
):
|
|
info = await billing_svc.get_active_subscription(user_id)
|
|
if info is None:
|
|
raise HTTPException(status_code=404, detail="User not found")
|
|
return {
|
|
"is_active": info.is_active,
|
|
"tariff_name": info.tariff.name if info.tariff else None,
|
|
"start_date": info.start_date,
|
|
"end_date": info.end_date,
|
|
"remaining_days": info.remaining_days,
|
|
}
|