Улучшение взаимодействия и добавление веб-приложения
This commit is contained in:
119
server.py
Normal file
119
server.py
Normal 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)
|
||||
Reference in New Issue
Block a user