"""Endpoint management API routes.""" from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from ..database import get_db from ..models.endpoint import Endpoint, ApplicationTemplate from ..models.gateway import Gateway from ..models.user import User, UserRole from ..models.access import UserGatewayAccess, UserEndpointAccess from ..schemas.endpoint import ( EndpointCreate, EndpointUpdate, EndpointResponse, ApplicationTemplateResponse ) from .deps import get_current_user, require_admin router = APIRouter() def user_has_gateway_access(db: Session, user: User, gateway_id: int) -> bool: """Check if user has access to gateway.""" if user.role == UserRole.SUPER_ADMIN: return True if user.role == UserRole.ADMIN: gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first() return gateway and gateway.tenant_id == user.tenant_id access = db.query(UserGatewayAccess).filter( UserGatewayAccess.user_id == user.id, UserGatewayAccess.gateway_id == gateway_id ).first() return access is not None @router.get("/templates", response_model=list[ApplicationTemplateResponse]) def list_application_templates( db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """List available application templates.""" templates = db.query(ApplicationTemplate).all() return templates @router.get("/gateway/{gateway_id}", response_model=list[EndpointResponse]) def list_endpoints_for_gateway( gateway_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """List endpoints for a gateway.""" if not user_has_gateway_access(db, current_user, gateway_id): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No access to this gateway" ) endpoints = db.query(Endpoint).filter(Endpoint.gateway_id == gateway_id).all() return endpoints @router.post("/gateway/{gateway_id}", response_model=EndpointResponse, status_code=status.HTTP_201_CREATED) def create_endpoint( gateway_id: int, endpoint_data: EndpointCreate, db: Session = Depends(get_db), current_user: User = Depends(require_admin) ): """Create a new endpoint for a gateway.""" gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first() if not gateway: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Gateway not found" ) # Check tenant access if current_user.role != UserRole.SUPER_ADMIN: if gateway.tenant_id != current_user.tenant_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Cannot add endpoints to gateways from other tenants" ) endpoint = Endpoint( **endpoint_data.model_dump(), gateway_id=gateway_id ) db.add(endpoint) db.commit() db.refresh(endpoint) return endpoint @router.get("/{endpoint_id}", response_model=EndpointResponse) def get_endpoint( endpoint_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Get endpoint by ID.""" endpoint = db.query(Endpoint).filter(Endpoint.id == endpoint_id).first() if not endpoint: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Endpoint not found" ) if not user_has_gateway_access(db, current_user, endpoint.gateway_id): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No access to this endpoint" ) return endpoint @router.put("/{endpoint_id}", response_model=EndpointResponse) def update_endpoint( endpoint_id: int, endpoint_data: EndpointUpdate, db: Session = Depends(get_db), current_user: User = Depends(require_admin) ): """Update endpoint.""" endpoint = db.query(Endpoint).filter(Endpoint.id == endpoint_id).first() if not endpoint: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Endpoint not found" ) gateway = db.query(Gateway).filter(Gateway.id == endpoint.gateway_id).first() # Check tenant access if current_user.role != UserRole.SUPER_ADMIN: if gateway.tenant_id != current_user.tenant_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Cannot modify endpoints from other tenants" ) update_data = endpoint_data.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(endpoint, field, value) db.commit() db.refresh(endpoint) return endpoint @router.delete("/{endpoint_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_endpoint( endpoint_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_admin) ): """Delete endpoint.""" endpoint = db.query(Endpoint).filter(Endpoint.id == endpoint_id).first() if not endpoint: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Endpoint not found" ) gateway = db.query(Gateway).filter(Gateway.id == endpoint.gateway_id).first() # Check tenant access if current_user.role != UserRole.SUPER_ADMIN: if gateway.tenant_id != current_user.tenant_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Cannot delete endpoints from other tenants" ) db.delete(endpoint) db.commit() @router.post("/{endpoint_id}/access/{user_id}", status_code=status.HTTP_201_CREATED) def grant_endpoint_access( endpoint_id: int, user_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_admin) ): """Grant user access to specific endpoint (fine-grained control).""" endpoint = db.query(Endpoint).filter(Endpoint.id == endpoint_id).first() if not endpoint: raise HTTPException(status_code=404, detail="Endpoint not found") user = db.query(User).filter(User.id == user_id).first() if not user: raise HTTPException(status_code=404, detail="User not found") existing = db.query(UserEndpointAccess).filter( UserEndpointAccess.endpoint_id == endpoint_id, UserEndpointAccess.user_id == user_id ).first() if existing: raise HTTPException(status_code=400, detail="Access already granted") access = UserEndpointAccess( user_id=user_id, endpoint_id=endpoint_id, granted_by_id=current_user.id ) db.add(access) db.commit() return {"message": "Access granted"} @router.delete("/{endpoint_id}/access/{user_id}", status_code=status.HTTP_204_NO_CONTENT) def revoke_endpoint_access( endpoint_id: int, user_id: int, db: Session = Depends(get_db), current_user: User = Depends(require_admin) ): """Revoke user access to endpoint.""" access = db.query(UserEndpointAccess).filter( UserEndpointAccess.endpoint_id == endpoint_id, UserEndpointAccess.user_id == user_id ).first() if not access: raise HTTPException(status_code=404, detail="Access not found") db.delete(access) db.commit()