"""WeCom webhook endpoints.""" from __future__ import annotations import json from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy.ext.asyncio import AsyncSession from ...core.database import get_db from ...services.integrations.wecom import get_wecom_service router = APIRouter() @router.get("/webhook") @router.get("/webhook/", include_in_schema=False) async def verify_webhook_url( msg_signature: str, timestamp: str, nonce: str, echostr: str, db: AsyncSession = Depends(get_db), ): """验证企业微信事件订阅 URL。""" try: service = get_wecom_service(db) await service.load_config(tenant_id=1) if not service.is_configured(): raise HTTPException(status_code=400, detail="请先配置企业微信") decrypted_echostr = service.verify_url(msg_signature, timestamp, nonce, echostr) return { "errcode": 0, "errmsg": "ok", "echostr": decrypted_echostr, } except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) except Exception as exc: raise HTTPException(status_code=500, detail=str(exc)) @router.post("/webhook") @router.post("/webhook/", include_in_schema=False) async def handle_wecom_event( request: Request, db: AsyncSession = Depends(get_db), ): """处理企业微信事件推送。""" try: msg_signature = request.headers.get("msg_signature", "") timestamp = request.headers.get("timestamp", "") nonce = request.headers.get("nonce", "") body_bytes = await request.body() body = body_bytes.decode("utf-8") service = get_wecom_service(db) await service.load_config(tenant_id=1) if not service.verify_callback(msg_signature, timestamp, nonce, body): raise HTTPException(status_code=401, detail="签名验证失败") decrypted = service._decrypt(body) event_data = json.loads(decrypted) if decrypted else {} await service.handle_message_event(event_data) return { "errcode": 0, "errmsg": "ok", } except HTTPException: raise except Exception as exc: print(f"[WeCom] Webhook error: {exc}") return {"errcode": 0, "errmsg": "ok"}