"""Webhook configuration CRUD router — admin only. Endpoints --------- GET /webhooks — list all webhook configs POST /webhooks — create a new webhook config GET /webhooks/{id} — get a single webhook config PATCH /webhooks/{id} — update a webhook config DELETE /webhooks/{id} — hard-delete a webhook config POST /webhooks/{id}/test — send a test ping """ import uuid from fastapi import APIRouter, Depends, status from sqlalchemy.orm import Session from app.database import get_db from app.dependencies.auth import require_any_role from app.domain.unit_of_work import UnitOfWork from app.models.user import User from app.schemas.webhook import WebhookConfigCreate, WebhookConfigOut, WebhookConfigUpdate from app.services.webhook_service import ( create_webhook, delete_webhook, dispatch_webhook, get_webhook_or_raise, list_webhooks, update_webhook, ) router = APIRouter(prefix="/webhooks", tags=["webhooks"]) def _mask_secret(wh) -> WebhookConfigOut: """Return a WebhookConfigOut with the secret masked.""" out = WebhookConfigOut.model_validate(wh) if wh.secret: out.secret = "***" else: out.secret = None return out # --------------------------------------------------------------------------- # GET /webhooks # --------------------------------------------------------------------------- @router.get("", response_model=list[WebhookConfigOut]) def list_webhooks_route( offset: int = 0, limit: int = 50, db: Session = Depends(get_db), current_user: User = Depends(require_any_role("red_lead", "blue_lead")), ): """Return all webhook configurations. **Requires admin role.**""" webhooks = list_webhooks(db, offset=offset, limit=limit) return [_mask_secret(wh) for wh in webhooks] # --------------------------------------------------------------------------- # POST /webhooks # --------------------------------------------------------------------------- @router.post("", response_model=WebhookConfigOut, status_code=status.HTTP_201_CREATED) def create_webhook_route( payload: WebhookConfigCreate, db: Session = Depends(get_db), current_user: User = Depends(require_any_role("red_lead", "blue_lead")), ): """Create a new webhook configuration. **Requires admin role.**""" with UnitOfWork(db) as uow: wh = create_webhook(db, created_by=current_user.id, payload=payload) uow.commit() db.refresh(wh) return _mask_secret(wh) # --------------------------------------------------------------------------- # GET /webhooks/{id} # --------------------------------------------------------------------------- @router.get("/{webhook_id}", response_model=WebhookConfigOut) def get_webhook_route( webhook_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(require_any_role("red_lead", "blue_lead")), ): """Return a single webhook configuration. **Requires admin role.**""" wh = get_webhook_or_raise(db, webhook_id) return _mask_secret(wh) # --------------------------------------------------------------------------- # PATCH /webhooks/{id} # --------------------------------------------------------------------------- @router.patch("/{webhook_id}", response_model=WebhookConfigOut) def update_webhook_route( webhook_id: uuid.UUID, payload: WebhookConfigUpdate, db: Session = Depends(get_db), current_user: User = Depends(require_any_role("red_lead", "blue_lead")), ): """Update one or more fields of a webhook configuration. **Requires admin role.**""" with UnitOfWork(db) as uow: wh = update_webhook(db, webhook_id, payload) uow.commit() db.refresh(wh) return _mask_secret(wh) # --------------------------------------------------------------------------- # DELETE /webhooks/{id} # --------------------------------------------------------------------------- @router.delete("/{webhook_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_webhook_route( webhook_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(require_any_role("red_lead", "blue_lead")), ): """Hard-delete a webhook configuration. **Requires admin role.**""" with UnitOfWork(db) as uow: delete_webhook(db, webhook_id) uow.commit() # --------------------------------------------------------------------------- # POST /webhooks/{id}/test # --------------------------------------------------------------------------- @router.post("/{webhook_id}/test", status_code=status.HTTP_202_ACCEPTED) def test_webhook_route( webhook_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(require_any_role("red_lead", "blue_lead")), ): """Send a test ping to the webhook endpoint. **Requires admin role.**""" # Verify the webhook exists before dispatching get_webhook_or_raise(db, webhook_id) dispatch_webhook("webhook.test", {"webhook_id": str(webhook_id), "message": "Test ping from Aegis"}) return {"detail": "Test ping dispatched"}