Улучшение взаимодействия и добавление веб-приложения

This commit is contained in:
2026-01-09 01:20:30 +03:00
parent eed252d52e
commit 2472947c1f
16 changed files with 2972 additions and 969 deletions

119
server.py Normal file
View File

@@ -0,0 +1,119 @@
from fastapi import FastAPI, HTTPException, Request
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import uvicorn
from datetime import datetime
import logging
import json
from database import db
from config import PLANS
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("server")
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.on_event("startup")
async def startup():
await db.connect()
logger.info("Database connected")
@app.get("/api/plans")
async def get_plans():
# Convert PLANS dict to list for easier frontend consumption
plans_list = []
for pid, p in PLANS.items():
plans_list.append({
"id": pid,
**p
})
return plans_list
from aiogram.types import LabeledPrice
from pydantic import BaseModel
class BuyPlanRequest(BaseModel):
user_id: int
plan_id: str
@app.post("/api/create-invoice")
async def create_invoice(req: BuyPlanRequest, request: Request):
bot = getattr(request.app.state, "bot", None)
if not bot:
return JSONResponse(status_code=500, content={"error": "Bot instance not initialized in app state"})
plan = PLANS.get(req.plan_id)
if not plan:
return JSONResponse(status_code=404, content={"error": "Plan not found"})
# Determine price in Stars (XTR). Assuming Plan Price in config is in RUB, need conversion or direct usage.
# Telegram Stars usually 1 Star ~= 0.013 USD? Or direct mapping.
# User's bot code uses currency="XTR" and prices=[LabeledPrice(..., amount=final_price)].
# Usually amount is in smallest units? XTR amount is integer number of stars.
# Assuming config price IS stars or directly usable.
price = plan['price']
try:
invoice_link = await bot.create_invoice_link(
title=f"Sub: {plan['name']}",
description=f"{plan['data_limit']}GB / {plan['days']} days",
payload=f"{req.plan_id}:", # Promo code empty for now
provider_token="", # Empty for Stars
currency="XTR",
prices=[LabeledPrice(label=plan['name'], amount=price)]
)
return {"invoice_link": invoice_link}
except Exception as e:
logger.error(f"Error generating invoice: {e}")
return JSONResponse(status_code=500, content={"error": str(e)})
@app.get("/api/user/{user_id}")
async def get_user_stats(user_id: int):
user = await db.get_user(user_id)
if not user:
return JSONResponse(status_code=404, content={"error": "User not found"})
sub_until = user['subscription_until']
days_left = 0
status = "Inactive"
expire_str = "-"
if sub_until:
if isinstance(sub_until, str):
try:
sub_until = datetime.fromisoformat(sub_until)
except:
pass
if isinstance(sub_until, datetime):
expire_str = sub_until.strftime("%Y-%m-%d")
if sub_until > datetime.now():
delta = sub_until - datetime.now()
days_left = delta.days
status = "Active"
else:
status = "Expired"
return {
"status": status,
"days_left": days_left,
"expire_date": expire_str,
"data_usage": user['data_limit'] or 0,
"plan": "Custom"
}
# Serve Static Files (must be last)
app.mount("/", StaticFiles(directory="web_app/static", html=True), name="static")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)