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

106 lines
5.9 KiB
Python
Executable File

from fastapi import FastAPI, HTTPException, UploadFile, File, 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 JWTError, jwt
import bcrypt, os, uuid, 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(password: str):
pwd_bytes = password.encode('utf-8')
return bcrypt.hashpw(pwd_bytes[:72], bcrypt.gensalt()).decode('utf-8')
def verify_password(plain, hashed):
return bcrypt.checkpw(plain.encode('utf-8')[:72], hashed.encode('utf-8'))
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return int(payload.get("sub"))
except: raise HTTPException(status_code=401)
# --- API ---
@app.post("/api/auth/register")
async def register(email: str = Form(...), password: str = Form(...)):
async with AsyncSessionLocal() as session:
async with session.begin():
h = get_password_hash(password)
await session.execute(text("INSERT INTO data.users (email, password_hash) VALUES (:e, :p)"), {"e": email, "p": h})
return {"status": "success"}
@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)
token = jwt.encode({"sub": str(u.id), "exp": datetime.utcnow() + timedelta(days=1)}, SECRET_KEY, algorithm=ALGORITHM)
return {"access_token": token, "token_type": "bearer"}
@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("/api/vehicles")
async def all_models():
async with AsyncSessionLocal() as session:
q = text("SELECT vm.id, m.name as brand, vm.model_name as model FROM ref.vehicle_models vm JOIN ref.vehicle_makes m ON vm.make_id = m.id ORDER BY brand, model")
res = await session.execute(q)
return [dict(r._mapping) for r in res.fetchall()]
class VehicleReg(BaseModel): model_id: int; vin: str; plate: str; mileage: int; purchase_date: date
@app.post("/api/register")
async def register_vehicle(d: VehicleReg, uid: int = Depends(get_current_user)):
async with AsyncSessionLocal() as session:
async with session.begin():
# Új jármű vagy meglévő
res = await session.execute(text("INSERT INTO data.vehicles (model_id, vin, current_plate) VALUES (:mid, :vin, :plt) RETURNING id"), {"mid": d.model_id, "vin": d.vin, "plt": d.plate})
vid = res.scalar()
await session.execute(text("INSERT INTO data.vehicle_history (vehicle_id, user_id, role, start_date, start_mileage) VALUES (:vid, :uid, 'OWNER', :sd, :sm)"), {"vid": vid, "uid": uid, "sd": d.purchase_date, "sm": d.mileage})
return {"status": "success"}
@app.get("/api/vehicle/{vid}")
async def get_details(vid: int, uid: int = Depends(get_current_user)):
async with AsyncSessionLocal() as session:
q = text("SELECT v.id, v.current_plate as plate, m.name as brand, mo.model_name as model, vh.start_mileage as mileage, v.status, u.default_currency as currency 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 JOIN data.users u ON vh.user_id = u.id WHERE v.id = :vid AND vh.user_id = :uid")
res = await session.execute(q, {"vid": vid, "uid": uid})
car = res.fetchone()
if not car: raise HTTPException(status_code=404)
# Idei költség
c_q = text("SELECT SUM(amount) FROM data.costs WHERE vehicle_id = :vid AND EXTRACT(YEAR FROM date) = 2026")
cost = (await session.execute(c_q, {"vid": vid})).scalar() or 0
return {**dict(car._mapping), "year_cost": cost}
@app.post("/api/add_cost")
async def add_cost(vehicle_id: int = Form(...), cost_type: str = Form(...), amount: float = Form(...), currency: str = Form(...), mileage: int = Form(...), date_str: str = Form(...), uid: int = Depends(get_current_user)):
async with AsyncSessionLocal() as session:
async with session.begin():
await session.execute(text("INSERT INTO data.costs (vehicle_id, user_id, cost_type, amount, currency, date, mileage_at_cost) VALUES (:vid, :uid, :type, :amt, :curr, :date, :mil)"),
{"vid": vehicle_id, "uid": uid, "type": cost_type, "amt": amount, "curr": currency, "date": date_str, "mil": mileage})
return {"status": "success"}
@app.get("/")
async def index(): return FileResponse("/app/frontend/index.html")