Files
service-finder/code-server-config/data/User/History/-3487e1e/sEal.py

81 lines
4.0 KiB
Python
Executable File

from fastapi import FastAPI, HTTPException, Form, Depends
from fastapi.responses import FileResponse, JSONResponse
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy import text
from datetime import datetime, timedelta, date
from jose import jwt
import bcrypt, os, traceback
from dotenv import load_dotenv
load_dotenv()
SECRET_KEY = "SZUPER_TITKOS_KULCS_2026"
ALGORITHM = "HS256"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/auth/login")
DATABASE_URL = os.getenv("DATABASE_URL", "").replace("postgresql://", "postgresql+asyncpg://")
engine = create_async_engine(DATABASE_URL, pool_pre_ping=True)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
app = FastAPI()
# --- AUTH ---
def get_password_hash(p): return bcrypt.hashpw(p.encode('utf-8')[:72], bcrypt.gensalt()).decode('utf-8')
def verify_password(p, h): return bcrypt.checkpw(p.encode('utf-8')[:72], h.encode('utf-8'))
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
p = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return int(p.get("sub"))
except: raise HTTPException(status_code=401)
@app.post("/api/auth/register")
async def register(email: str = Form(...), password: str = Form(...)):
try:
async with AsyncSessionLocal() as session:
async with session.begin():
await session.execute(text("INSERT INTO data.users (email, password_hash) VALUES (:e, :p)"),
{"e": email, "p": get_password_hash(password)})
return {"status": "success"}
except Exception as e:
return JSONResponse(status_code=400, content={"detail": "Email már létezik vagy adatbázis hiba."})
@app.post("/api/auth/login")
async def login(f: OAuth2PasswordRequestForm = Depends()):
async with AsyncSessionLocal() as session:
res = await session.execute(text("SELECT id, password_hash FROM data.users WHERE email = :e"), {"e": f.username})
u = res.fetchone()
if not u or not verify_password(f.password, u.password_hash): raise HTTPException(status_code=401, detail="Hibás adatok")
t = jwt.encode({"sub": str(u.id), "exp": datetime.utcnow() + timedelta(days=1)}, SECRET_KEY, algorithm=ALGORITHM)
return {"access_token": t, "token_type": "bearer"}
# --- DATA ---
@app.get("/api/meta/vehicle-hierarchy")
async def get_hierarchy():
async with AsyncSessionLocal() as session:
q = text("SELECT vm.category, m.name as brand, vm.id as model_id, vm.model_name FROM ref.vehicle_models vm JOIN ref.vehicle_makes m ON vm.make_id = m.id ORDER BY vm.category, m.name")
res = await session.execute(q)
h = {}
for r in res:
if r.category not in h: h[r.category] = {}
if r.brand not in h[r.category]: h[r.category][r.brand] = []
h[r.category][r.brand].append({"id": r.model_id, "name": r.model_name})
return h
@app.get("/api/meta/cost-types")
async def get_cost_types():
async with AsyncSessionLocal() as session:
res = await session.execute(text("SELECT code, name FROM ref.cost_types ORDER BY name"))
return {r.code: r.name for r in res.fetchall()}
@app.get("/api/my_vehicles")
async def my_vehicles(uid: int = Depends(get_current_user)):
async with AsyncSessionLocal() as session:
q = text("SELECT v.id as vehicle_id, v.current_plate as plate, m.name as brand, mo.model_name as model, v.status FROM data.vehicle_history vh JOIN data.vehicles v ON vh.vehicle_id = v.id JOIN ref.vehicle_models mo ON v.model_id = mo.id JOIN ref.vehicle_makes m ON mo.make_id = m.id WHERE vh.user_id = :uid AND vh.end_date IS NULL")
res = await session.execute(q, {"uid": uid})
return [dict(r._mapping) for r in res.fetchall()]
@app.get("/")
async def index(): return FileResponse("/app/frontend/index.html")