232 lines
7.2 KiB
Python
232 lines
7.2 KiB
Python
"""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()
|