Initial commit: Robot ökoszisztéma v2.0 - Stabilizált jármű és szerviz robotok

This commit is contained in:
Kincses
2026-03-04 02:03:03 +01:00
commit 250f4f4b8f
7942 changed files with 449625 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
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
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()
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)
# --- METAADATOK ---
@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)
hierarchy = {}
for r in res:
if r.category not in hierarchy: hierarchy[r.category] = {}
if r.brand not in hierarchy[r.category]: hierarchy[r.category][r.brand] = []
hierarchy[r.category][r.brand].append({"id": r.model_id, "name": r.model_name})
return hierarchy
@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()}
# --- JÁRMŰ MŰVELETEK ---
@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,
(SELECT SUM(amount) FROM data.costs WHERE vehicle_id = v.id) as total_cost
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.post("/api/register")
async def register_vehicle(d: dict, uid: int = Depends(get_current_user)):
async with AsyncSessionLocal() as session:
async with session.begin():
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', CURRENT_DATE, :sm)"), {"vid": vid, "uid": uid, "sm": d['mileage']})
return {"status": "success"}
@app.delete("/api/vehicle/{vid}")
async def delete_vehicle(vid: int, uid: int = Depends(get_current_user)):
async with AsyncSessionLocal() as session:
async with session.begin():
# Soft delete: lezárjuk a history-t
await session.execute(text("UPDATE data.vehicle_history SET end_date = CURRENT_DATE WHERE vehicle_id = :vid AND user_id = :uid"), {"vid": vid, "uid": uid})
return {"status": "deleted"}
@app.post("/api/add_cost")
async def add_cost(d: dict, 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) VALUES (:vid, :uid, :type, :amt, 'HUF', CURRENT_DATE)"),
{"vid": d['vehicle_id'], "uid": uid, "type": d['type'], "amt": d['amount']})
return {"status": "success"}
@app.get("/")
async def index(): return FileResponse("/app/frontend/index.html")