from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy.orm import Session from typing import List from .. import models, schemas from ..database import get_db import datetime router = APIRouter(tags=["diagrams"]) @router.get("/", response_model=List[schemas.DiagramSummary]) def list_diagrams(db: Session = Depends(get_db)): return db.query(models.Diagram).order_by(models.Diagram.updated_at.desc()).all() @router.post("/", response_model=schemas.DiagramSummary) def create_diagram(diagram: schemas.DiagramCreate, db: Session = Depends(get_db)): db_diagram = models.Diagram(**diagram.model_dump()) db.add(db_diagram) db.commit() db.refresh(db_diagram) return db_diagram @router.get("/{diagram_id}", response_model=schemas.DiagramFull) def get_diagram(diagram_id: int, db: Session = Depends(get_db)): diagram = db.query(models.Diagram).filter(models.Diagram.id == diagram_id).first() if not diagram: raise HTTPException(status_code=404, detail="Diagram not found") return diagram @router.patch("/{diagram_id}", response_model=schemas.DiagramSummary) def update_diagram(diagram_id: int, update: schemas.DiagramUpdate, db: Session = Depends(get_db)): diagram = db.query(models.Diagram).filter(models.Diagram.id == diagram_id).first() if not diagram: raise HTTPException(status_code=404, detail="Diagram not found") for key, value in update.model_dump(exclude_none=True).items(): setattr(diagram, key, value) diagram.updated_at = datetime.datetime.utcnow() db.commit() db.refresh(diagram) return diagram @router.delete("/{diagram_id}") def delete_diagram(diagram_id: int, db: Session = Depends(get_db)): diagram = db.query(models.Diagram).filter(models.Diagram.id == diagram_id).first() if not diagram: raise HTTPException(status_code=404, detail="Diagram not found") db.delete(diagram) db.commit() return {"ok": True} @router.post("/{diagram_id}/duplicate", response_model=schemas.DiagramSummary, status_code=201) def duplicate_diagram(diagram_id: int, db: Session = Depends(get_db)): src = db.query(models.Diagram).filter(models.Diagram.id == diagram_id).first() if not src: raise HTTPException(status_code=404, detail="Diagram not found") new_diag = models.Diagram(name=f"{src.name} (copy)", description=src.description or "") db.add(new_diag) db.flush() id_map = {} for dev in src.devices: new_dev = models.Device( diagram_id=new_diag.id, device_type=dev.device_type, label=dev.label, reference=dev.reference, x=dev.x + 30, y=dev.y + 30, width=dev.width, height=dev.height, properties=dev.properties, pins=dev.pins, ) db.add(new_dev) db.flush() id_map[dev.id] = new_dev.id for wire in src.wires: new_wire = models.Wire( diagram_id=new_diag.id, label=wire.label, from_device_id=id_map.get(wire.from_device_id), from_pin=wire.from_pin, to_device_id=id_map.get(wire.to_device_id), to_pin=wire.to_pin, color_primary=wire.color_primary, color_stripe=wire.color_stripe, gauge=wire.gauge, length=wire.length, length_unit=wire.length_unit, notes=wire.notes or "", waypoints=wire.waypoints or [], twisted_pair=wire.twisted_pair, twist_pitch=wire.twist_pitch, shielded=wire.shielded, show_size_label=wire.show_size_label, ) db.add(new_wire) db.commit() db.refresh(new_diag) return new_diag @router.post("/import", response_model=schemas.DiagramSummary, status_code=201) async def import_diagram(request: Request, db: Session = Depends(get_db)): data = await request.json() new_diag = models.Diagram( name=data.get("name", "Imported Diagram"), description=data.get("description", ""), ) db.add(new_diag) db.flush() id_map = {} for dev_data in data.get("devices", []): new_dev = models.Device( diagram_id=new_diag.id, device_type=dev_data.get("device_type", "generic"), label=dev_data.get("label", ""), reference=dev_data.get("reference", ""), x=dev_data.get("x", 100), y=dev_data.get("y", 100), width=dev_data.get("width", 120), height=dev_data.get("height", 60), properties=dev_data.get("properties", {}), pins=dev_data.get("pins", []), ) db.add(new_dev) db.flush() if "id" in dev_data: id_map[dev_data["id"]] = new_dev.id for wire_data in data.get("wires", []): new_wire = models.Wire( diagram_id=new_diag.id, label=wire_data.get("label", ""), from_device_id=id_map.get(wire_data.get("from_device_id")), from_pin=wire_data.get("from_pin", ""), to_device_id=id_map.get(wire_data.get("to_device_id")), to_pin=wire_data.get("to_pin", ""), color_primary=wire_data.get("color_primary", "#FF0000"), color_stripe=wire_data.get("color_stripe"), gauge=wire_data.get("gauge", "18 AWG"), length=wire_data.get("length"), length_unit=wire_data.get("length_unit", "in"), notes=wire_data.get("notes", ""), waypoints=wire_data.get("waypoints", []), twisted_pair=wire_data.get("twisted_pair", False), twist_pitch=wire_data.get("twist_pitch", 16.0), shielded=wire_data.get("shielded", False), show_size_label=wire_data.get("show_size_label", False), ) db.add(new_wire) db.commit() db.refresh(new_diag) return new_diag