"""Server inventory routes (customer-scoped). No direct connectivity from the central server - health checks are HEALTH_CHECK jobs executed by the customer's satellite. """ from fastapi import APIRouter, Depends, Request from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import client_ip, get_current_user from app.core.database import get_db from app.core.exceptions import ConflictError, NotFoundError from app.models.customer import Customer from app.models.server import Server from app.models.user import User from app.schemas.server import ServerCreate, ServerRead, ServerUpdate from app.services.audit import AuditService router = APIRouter() @router.get("", response_model=list[ServerRead]) async def list_servers( customer_id: int | None = None, db: AsyncSession = Depends(get_db), _user: User = Depends(get_current_user), ) -> list[Server]: stmt = select(Server).order_by(Server.name) if customer_id is not None: stmt = stmt.where(Server.customer_id == customer_id) result = await db.execute(stmt) return list(result.scalars().all()) @router.post("", response_model=ServerRead, status_code=201) async def create_server( payload: ServerCreate, request: Request, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> Server: customer = await db.get(Customer, payload.customer_id) if not customer: raise NotFoundError("Kunde nicht gefunden") existing = await db.execute( select(Server).where( Server.customer_id == payload.customer_id, Server.name == payload.name ) ) if existing.scalar_one_or_none(): raise ConflictError("Server mit diesem Namen existiert beim Kunden bereits") server = Server(**payload.model_dump()) db.add(server) await db.flush() await AuditService(db).log( username=user.username, action="server.create", target=server.name, customer_id=customer.id, ip_address=client_ip(request), ) return server @router.get("/{server_id}", response_model=ServerRead) async def get_server( server_id: int, db: AsyncSession = Depends(get_db), _user: User = Depends(get_current_user), ) -> Server: server = await db.get(Server, server_id) if not server: raise NotFoundError("Server nicht gefunden") return server @router.patch("/{server_id}", response_model=ServerRead) async def update_server( server_id: int, payload: ServerUpdate, request: Request, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> Server: server = await db.get(Server, server_id) if not server: raise NotFoundError("Server nicht gefunden") for field, value in payload.model_dump(exclude_unset=True).items(): setattr(server, field, value) await AuditService(db).log( username=user.username, action="server.update", target=server.name, customer_id=server.customer_id, ip_address=client_ip(request), ) return server @router.delete("/{server_id}", status_code=204) async def delete_server( server_id: int, request: Request, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> None: server = await db.get(Server, server_id) if not server: raise NotFoundError("Server nicht gefunden") await AuditService(db).log( username=user.username, action="server.delete", target=server.name, customer_id=server.customer_id, ip_address=client_ip(request), ) await db.delete(server)