| import logging |
| from typing import Any, Dict, List, Optional |
| from fastapi import Depends, Request |
| from pydantic import BaseModel |
| from sqlalchemy.orm import Session |
|
|
| from core.api_governance import ActionComplexity, require_governance |
| from core.auth import get_current_user |
| from core.base_routes import BaseAPIRouter |
| from core.connection_service import connection_service |
| from core.database import get_db |
| from core.models import User |
|
|
| router = BaseAPIRouter(prefix="/api/v1/connections", tags=["Connections"]) |
| logger = logging.getLogger(__name__) |
|
|
| class ConnectionResponse(BaseModel): |
| id: str |
| name: str |
| integration_id: str |
| status: str |
| created_at: Optional[str] = None |
| last_used: Optional[str] = None |
|
|
| @router.get("/", response_model=List[ConnectionResponse]) |
| async def list_connections(integration_id: Optional[str] = None, current_user: User = Depends(get_current_user)): |
| return connection_service.get_connections(current_user.id, integration_id) |
|
|
| @router.delete("/{connection_id}") |
| @require_governance( |
| action_complexity=ActionComplexity.HIGH, |
| action_name="delete_connection", |
| feature="connection" |
| ) |
| async def delete_connection( |
| connection_id: str, |
| request: Request, |
| current_user: User = Depends(get_current_user), |
| db: Session = Depends(get_db), |
| agent_id: Optional[str] = None |
| ): |
| """ |
| Delete a connection. |
| |
| **Governance**: Requires SUPERVISED+ maturity (HIGH complexity). |
| - Connection deletion is a state-changing operation |
| - Requires SUPERVISED maturity or higher |
| """ |
| success = connection_service.delete_connection(connection_id, current_user.id) |
| if not success: |
| raise router.not_found_error("Connection", connection_id) |
|
|
| logger.info(f"Connection deleted: {connection_id}") |
| return router.success_response(message="Connection deleted successfully") |
|
|
| class RenameConnectionRequest(BaseModel): |
| name: str |
|
|
| @router.patch("/{connection_id}") |
| @require_governance( |
| action_complexity=ActionComplexity.MODERATE, |
| action_name="rename_connection", |
| feature="connection" |
| ) |
| async def rename_connection( |
| connection_id: str, |
| req: RenameConnectionRequest, |
| request: Request, |
| current_user: User = Depends(get_current_user), |
| db: Session = Depends(get_db), |
| agent_id: Optional[str] = None |
| ): |
| """ |
| Rename a connection. |
| |
| **Governance**: Requires INTERN+ maturity (MODERATE complexity). |
| - Connection modification is a moderate action |
| - Requires INTERN maturity or higher |
| """ |
| success = connection_service.update_connection_name(connection_id, current_user.id, req.name) |
| if not success: |
| raise router.not_found_error("Connection", connection_id) |
|
|
| logger.info(f"Connection renamed: {connection_id}") |
| return router.success_response(message="Connection renamed successfully") |
|
|
| @router.get("/{connection_id}/credentials") |
| async def get_credentials(connection_id: str, current_user: User = Depends(get_current_user)): |
| """ |
| Internal use only / Dev only. In production, we should never expose raw credentials. |
| """ |
| creds = connection_service.get_connection_credentials(connection_id, current_user.id) |
| if not creds: |
| raise router.not_found_error("Connection", connection_id) |
| return router.success_response(data=creds, message="Credentials retrieved") |
|
|