67 lines
2.5 KiB
Python
67 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
import time
|
|
from typing import Any, Dict
|
|
|
|
import httpx
|
|
|
|
from app.config.settings import get_settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_token_cache: Dict[str, Any] = {"token": "", "expires_at": 0.0}
|
|
|
|
|
|
class FeishuClient:
|
|
def __init__(self) -> None:
|
|
self.settings = get_settings()
|
|
|
|
async def _get_tenant_token(self) -> str:
|
|
if _token_cache["token"] and time.time() < _token_cache["expires_at"]:
|
|
return _token_cache["token"]
|
|
|
|
url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
|
|
payload = {
|
|
"app_id": self.settings.feishu_app_id,
|
|
"app_secret": self.settings.feishu_app_secret,
|
|
}
|
|
async with httpx.AsyncClient(timeout=self.settings.request_timeout) as client:
|
|
resp = await client.post(url, json=payload)
|
|
resp.raise_for_status()
|
|
data = resp.json()
|
|
token = data.get("tenant_access_token", "")
|
|
expire = int(data.get("expire", 0))
|
|
_token_cache["token"] = token
|
|
_token_cache["expires_at"] = time.time() + max(expire - 60, 0)
|
|
return token
|
|
|
|
async def get_approval_instance(self, instance_id: str) -> Dict[str, Any]:
|
|
token = await self._get_tenant_token()
|
|
url = f"https://open.feishu.cn/open-apis/approval/v4/instances/{instance_id}"
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
async with httpx.AsyncClient(timeout=self.settings.request_timeout) as client:
|
|
resp = await client.get(url, headers=headers)
|
|
resp.raise_for_status()
|
|
return resp.json()
|
|
|
|
async def subscribe_approval(self, approval_code: str) -> Dict[str, Any]:
|
|
token = await self._get_tenant_token()
|
|
url = (
|
|
"https://open.feishu.cn/open-apis/approval/v4/approvals/"
|
|
f"{approval_code}/subscribe"
|
|
)
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
async with httpx.AsyncClient(timeout=self.settings.request_timeout) as client:
|
|
resp = await client.post(url, headers=headers)
|
|
data = {}
|
|
try:
|
|
data = resp.json()
|
|
except Exception:
|
|
data = {}
|
|
code = data.get("code")
|
|
if resp.status_code != 200 and code != 1390007:
|
|
logger.error("订阅审批定义失败: status=%s body=%s", resp.status_code, resp.text)
|
|
resp.raise_for_status()
|
|
return data
|