133 lines
3.6 KiB
Python
133 lines
3.6 KiB
Python
"""
|
|
Endpoints API pour l'éditeur d'architecture
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
from pydantic import BaseModel
|
|
from typing import List, Optional, Dict, Any
|
|
from uuid import uuid4
|
|
from datetime import datetime
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from backend.app.core.database import get_arch_db
|
|
from backend.app.models.architecture import ArchitectureNode
|
|
|
|
router = APIRouter(prefix="/api/architecture", tags=["Architecture"])
|
|
DATA_DIR = Path(__file__).resolve().parents[3] / "data"
|
|
WORLD_FILE = DATA_DIR / "architecture.json"
|
|
|
|
|
|
class ArchitectureNodeCreate(BaseModel):
|
|
id: Optional[str] = None
|
|
type: str
|
|
x: int
|
|
y: int
|
|
width: int
|
|
height: int
|
|
rotation: int = 0
|
|
payload: Dict[str, Any]
|
|
|
|
|
|
class ArchitectureNodeResponse(BaseModel):
|
|
id: str
|
|
type: str
|
|
x: int
|
|
y: int
|
|
width: int
|
|
height: int
|
|
rotation: int
|
|
payload: Dict[str, Any]
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ArchitectureWorldPayload(BaseModel):
|
|
items: List[Dict[str, Any]]
|
|
splines: Optional[List[Dict[str, Any]]] = None
|
|
|
|
|
|
@router.get("/nodes", response_model=List[ArchitectureNodeResponse])
|
|
async def list_nodes(db: Session = Depends(get_arch_db)):
|
|
"""Liste tous les noeuds d'architecture"""
|
|
nodes = db.query(ArchitectureNode).order_by(ArchitectureNode.created_at.asc()).all()
|
|
results = []
|
|
for node in nodes:
|
|
try:
|
|
payload = json.loads(node.payload or "{}")
|
|
except json.JSONDecodeError:
|
|
payload = {}
|
|
results.append(ArchitectureNodeResponse(
|
|
id=node.id,
|
|
type=node.type,
|
|
x=node.x,
|
|
y=node.y,
|
|
width=node.width,
|
|
height=node.height,
|
|
rotation=node.rotation,
|
|
payload=payload,
|
|
created_at=node.created_at
|
|
))
|
|
return results
|
|
|
|
|
|
@router.post("/nodes", response_model=ArchitectureNodeResponse)
|
|
async def create_node(payload: ArchitectureNodeCreate, db: Session = Depends(get_arch_db)):
|
|
"""Créer un noeud d'architecture"""
|
|
node_id = payload.id or str(uuid4())
|
|
node = ArchitectureNode(
|
|
id=node_id,
|
|
type=payload.type,
|
|
x=payload.x,
|
|
y=payload.y,
|
|
width=payload.width,
|
|
height=payload.height,
|
|
rotation=payload.rotation,
|
|
payload=json.dumps(payload.payload)
|
|
)
|
|
db.add(node)
|
|
db.commit()
|
|
db.refresh(node)
|
|
return ArchitectureNodeResponse(
|
|
id=node.id,
|
|
type=node.type,
|
|
x=node.x,
|
|
y=node.y,
|
|
width=node.width,
|
|
height=node.height,
|
|
rotation=node.rotation,
|
|
payload=payload.payload,
|
|
created_at=node.created_at
|
|
)
|
|
|
|
|
|
def ensure_world_file() -> None:
|
|
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
if not WORLD_FILE.exists():
|
|
WORLD_FILE.write_text(json.dumps({"items": [], "splines": []}, indent=2), encoding="utf-8")
|
|
|
|
|
|
@router.get("/world")
|
|
async def get_world():
|
|
"""Charge le fichier architecture.json, le crée si absent."""
|
|
ensure_world_file()
|
|
try:
|
|
data = json.loads(WORLD_FILE.read_text(encoding="utf-8"))
|
|
except json.JSONDecodeError:
|
|
data = {"items": [], "splines": []}
|
|
return data
|
|
|
|
|
|
@router.post("/world")
|
|
async def save_world(payload: ArchitectureWorldPayload):
|
|
"""Sauvegarde les éléments du world dans architecture.json."""
|
|
ensure_world_file()
|
|
splines = payload.splines or []
|
|
WORLD_FILE.write_text(
|
|
json.dumps({"items": payload.items, "splines": splines}, indent=2),
|
|
encoding="utf-8"
|
|
)
|
|
return {"status": "ok", "count": len(payload.items), "splines": len(splines)}
|