import logging import httpx logger = logging.getLogger(__name__) API_V2_BASE = "https://api.clickup.com/api/v2" async def create_webhook( workspace_id: str, api_token: str, endpoint_url: str, events: list[str], *, space_id: str | None = None, folder_id: str | None = None, list_id: str | None = None, ) -> dict: url = f"{API_V2_BASE}/team/{workspace_id}/webhook" headers = {"Authorization": api_token, "Content-Type": "application/json"} payload: dict = { "endpoint": endpoint_url, "events": events, } if space_id: payload["space_id"] = space_id if folder_id: payload["folder_id"] = folder_id if list_id: payload["list_id"] = list_id async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.post(url, json=payload, headers=headers) if resp.status_code in (200, 201): return resp.json() error_text = resp.text[:500] raise RuntimeError(f"创建 webhook 失败 (HTTP {resp.status_code}): {error_text}") async def list_webhooks(workspace_id: str, api_token: str) -> list[dict]: url = f"{API_V2_BASE}/team/{workspace_id}/webhook" headers = {"Authorization": api_token} async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.get(url, headers=headers) if resp.status_code == 200: data = resp.json() return data.get("webhooks", []) error_text = resp.text[:500] raise RuntimeError(f"获取 webhook 列表失败 (HTTP {resp.status_code}): {error_text}") async def update_webhook(webhook_id: str, api_token: str, **updates) -> dict: url = f"{API_V2_BASE}/webhook/{webhook_id}" headers = {"Authorization": api_token, "Content-Type": "application/json"} async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.put(url, json=updates, headers=headers) if resp.status_code == 200: return resp.json() error_text = resp.text[:500] raise RuntimeError(f"更新 webhook 失败 (HTTP {resp.status_code}): {error_text}") async def delete_webhook(webhook_id: str, api_token: str) -> dict: url = f"{API_V2_BASE}/webhook/{webhook_id}" headers = {"Authorization": api_token} async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.delete(url, headers=headers) if resp.status_code in (200, 204): return {"deleted": True, "webhook_id": webhook_id} error_text = resp.text[:500] raise RuntimeError(f"删除 webhook 失败 (HTTP {resp.status_code}): {error_text}")