test api
This commit is contained in:
2
api/README.md
Normal file
2
api/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Для запуска API отдельно:
|
||||
# uvicorn api.main:app --reload
|
||||
15
api/config.py
Normal file
15
api/config.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from pydantic import BaseSettings
|
||||
import os
|
||||
|
||||
class Settings(BaseSettings):
|
||||
DB_USER: str = os.getenv("DB_USER", "postgres")
|
||||
DB_PASS: str = os.getenv("DB_PASS", "secretpassword")
|
||||
DB_NAME: str = os.getenv("DB_NAME", "vpn_bot_db")
|
||||
DB_HOST: str = os.getenv("DB_HOST", "db")
|
||||
DB_PORT: str = os.getenv("DB_PORT", "5432")
|
||||
DATABASE_URL: str = os.getenv(
|
||||
"DATABASE_URL",
|
||||
f"postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
|
||||
)
|
||||
|
||||
settings = Settings()
|
||||
7
api/db/connection.py
Normal file
7
api/db/connection.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from api.config import settings
|
||||
|
||||
DATABASE_URL = settings.DATABASE_URL
|
||||
engine = create_async_engine(DATABASE_URL, echo=False, future=True)
|
||||
SessionLocal = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)
|
||||
34
api/db/subscription.py
Normal file
34
api/db/subscription.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from api.db.connection import engine, SessionLocal
|
||||
from api.models.subscription import Subscription
|
||||
from api.models.base import Base
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
async def init_db():
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
async def set_subscription(user_id: int, uuid: str, until: datetime):
|
||||
async with SessionLocal() as session:
|
||||
sub = await session.get(Subscription, user_id)
|
||||
if sub:
|
||||
sub.uuid = uuid
|
||||
sub.until = until
|
||||
else:
|
||||
sub = Subscription(user_id=user_id, uuid=uuid, until=until)
|
||||
session.add(sub)
|
||||
await session.commit()
|
||||
|
||||
async def get_subscription(user_id: int):
|
||||
async with SessionLocal() as session:
|
||||
sub = await session.get(Subscription, user_id)
|
||||
if sub:
|
||||
return {"uuid": sub.uuid, "until": sub.until}
|
||||
return None
|
||||
|
||||
async def extend_subscription(user_id: int, months: int):
|
||||
sub = await get_subscription(user_id)
|
||||
if sub:
|
||||
new_until = max(sub["until"], datetime.now()) + timedelta(days=30*months)
|
||||
await set_subscription(user_id, sub["uuid"], new_until)
|
||||
return new_until
|
||||
return None
|
||||
13
api/main.py
Normal file
13
api/main.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import asyncio
|
||||
from fastapi import FastAPI
|
||||
from api.route import default, subscription
|
||||
from api.db.subscription import init_db
|
||||
|
||||
app = FastAPI(title="VPN Bot API")
|
||||
|
||||
@app.on_event("startup")
|
||||
async def on_startup():
|
||||
await init_db()
|
||||
|
||||
app.include_router(default.router)
|
||||
app.include_router(subscription.router)
|
||||
3
api/models/base.py
Normal file
3
api/models/base.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from sqlalchemy.orm import declarative_base
|
||||
|
||||
Base = declarative_base()
|
||||
8
api/models/subscription.py
Normal file
8
api/models/subscription.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from sqlalchemy import Column, String, DateTime
|
||||
from api.models.base import Base
|
||||
|
||||
class Subscription(Base):
|
||||
__tablename__ = 'subscriptions'
|
||||
uuid = Column(String, primary_key=True, index=True)
|
||||
user_id = Column(String, nullable=False, index=True)
|
||||
until = Column(DateTime, nullable=False)
|
||||
17
api/route/default.py
Normal file
17
api/route/default.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from fastapi import APIRouter
|
||||
import toml
|
||||
from pathlib import Path
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/")
|
||||
async def root():
|
||||
version = "dev"
|
||||
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
|
||||
if pyproject_path.exists():
|
||||
try:
|
||||
data = toml.load(pyproject_path)
|
||||
version = data.get("project", {}).get("version", "dev")
|
||||
except Exception:
|
||||
pass
|
||||
return {"status": "ok", "msg": "VPN Bot API", "version": version}
|
||||
39
api/route/subscription.py
Normal file
39
api/route/subscription.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from api.db.subscription import get_subscription, set_subscription, extend_subscription
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
router = APIRouter(prefix="/subscription", tags=["subscription"])
|
||||
|
||||
class SubscriptionInfo(BaseModel):
|
||||
user_id: int
|
||||
uuid: str
|
||||
until: datetime
|
||||
|
||||
class SubscriptionCreate(BaseModel):
|
||||
user_id: int
|
||||
months: int
|
||||
|
||||
@router.get("/{user_id}", response_model=Optional[SubscriptionInfo])
|
||||
async def get_user_subscription(user_id: int):
|
||||
sub = await get_subscription(user_id)
|
||||
if not sub:
|
||||
return None
|
||||
return SubscriptionInfo(user_id=user_id, uuid=sub["uuid"], until=sub["until"])
|
||||
|
||||
@router.post("/new", response_model=SubscriptionInfo)
|
||||
async def create_subscription(data: SubscriptionCreate):
|
||||
sub_id = str(uuid.uuid4())
|
||||
until = datetime.now() + timedelta(days=30*data.months)
|
||||
await set_subscription(data.user_id, sub_id, until)
|
||||
return SubscriptionInfo(user_id=data.user_id, uuid=sub_id, until=until)
|
||||
|
||||
@router.post("/extend", response_model=SubscriptionInfo)
|
||||
async def extend_user_subscription(data: SubscriptionCreate):
|
||||
new_until = await extend_subscription(data.user_id, data.months)
|
||||
if not new_until:
|
||||
raise HTTPException(status_code=404, detail="Subscription not found")
|
||||
sub = await get_subscription(data.user_id)
|
||||
return SubscriptionInfo(user_id=data.user_id, uuid=sub["uuid"], until=new_until)
|
||||
Reference in New Issue
Block a user