from __future__ import annotations import json from typing import Any from fastapi import APIRouter, Request, status from fastapi.responses import JSONResponse, PlainTextResponse from yuxi.channels.manager import channel_manager from yuxi.utils.logging_config import logger slack_webhook = APIRouter(tags=["slack-webhook"]) @slack_webhook.post("/api/webhook/slack") async def slack_event_receiver(request: Request): adapter = channel_manager._adapters.get("slack") if not adapter: return JSONResponse( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, content={"error": "Slack adapter is not running"}, ) body = await request.body() headers = dict(request.headers) if not await adapter.verify_webhook_signature(headers, body): return JSONResponse( status_code=status.HTTP_403_FORBIDDEN, content={"error": "Invalid webhook signature"}, ) try: payload: dict[str, Any] = json.loads(body.decode("utf-8")) except (json.JSONDecodeError, UnicodeDecodeError) as e: logger.error(f"Slack webhook: failed to parse JSON body: {e}") return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content={"error": "Invalid JSON body"}, ) event_type = payload.get("type", "") if event_type == "url_verification": challenge = payload.get("challenge", "") logger.info("Slack URL verification challenge received, responding with challenge") return PlainTextResponse(content=challenge, status_code=200) if event_type == "event_callback": try: await adapter._handle_http_event(payload) except Exception as e: logger.error(f"Slack webhook event handling error: {e}", exc_info=True) return JSONResponse(content={"ok": True}) logger.debug(f"Slack webhook: unhandled event type '{event_type}'") return JSONResponse(content={"ok": True})