annator-command-center / api /routes /webhooks /teams_webhooks.py
techprotrade's picture
Deploy ATOM FastAPI command center runtime (part 2)
a10e62e verified
Raw
History Blame Contribute Delete
2.24 kB
import logging
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Header, Request, Body
from sqlalchemy.orm import Session
from core.database import get_db
from core.integration_registry import IntegrationRegistry
from core.tenant_discovery import TenantDiscoveryService
from core.communication.adapters.teams import TeamsAdapter
from api.routes.webhooks.base import get_webhook_registry
from api.routes.webhooks.webhook_bridge import webhook_bridge
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/teams", tags=["Microsoft Teams Webhooks"])
@router.post("")
async def teams_webhook(
request: Request,
db: Session = Depends(get_db),
registry: IntegrationRegistry = Depends(get_webhook_registry)
):
"""
Unified Microsoft Teams webhook callback.
Handles JWT verification and dispatches via UCB.
"""
body = await request.body()
try:
data = await request.json()
except Exception:
raise HTTPException(status_code=400, detail="Invalid JSON")
# 1. Tenant Resolution
# Teams usually provides tenantId in the activity object
ms_tenant_id = data.get("conversation", {}).get("tenantId")
if not ms_tenant_id:
ms_tenant_id = data.get("channelData", {}).get("tenant", {}).get("id")
if not ms_tenant_id:
logger.warning("Teams webhook missing tenantId")
raise HTTPException(status_code=400, detail="Missing tenantId")
discoverer = TenantDiscoveryService(db)
tenant_id = await discoverer.get_tenant_id_by_external_id("teams", ms_tenant_id)
if not tenant_id:
logger.warning(f"No tenant found for Microsoft Teams tenantId: {ms_tenant_id}")
return {"status": "ignored", "reason": "tenant_not_found"}
# 2. Security Verification
adapter = TeamsAdapter()
if not await adapter.verify_request(request, body):
logger.error(f"Unauthorized Teams webhook for tenant {tenant_id}")
raise HTTPException(status_code=401, detail="Invalid signature")
# 3. Dispatch via Webhook Bridge
result = await webhook_bridge.process_event(
"teams",
tenant_id,
data,
registry,
db
)
return result