Initial commit: VPN Control Panel
- 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
This commit is contained in:
83
app/api/v1/users.py
Normal file
83
app/api/v1/users.py
Normal file
@@ -0,0 +1,83 @@
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user