import logging import httpx logger = logging.getLogger(__name__) MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create" MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get" MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete" MENU_ADD_CONDITIONAL_URL = "https://api.weixin.qq.com/cgi-bin/menu/addconditional" MENU_DEL_CONDITIONAL_URL = "https://api.weixin.qq.com/cgi-bin/menu/delconditional" class WeChatMenu: def __init__(self, gateway): self._gateway = gateway async def create(self, buttons: list[dict]) -> bool: token = self._gateway.access_token if self._gateway else None if not token: return False payload = {"button": buttons} try: async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.post(f"{MENU_CREATE_URL}?access_token={token}", json=payload) data = resp.json() return data.get("errcode") == 0 except Exception: logger.exception("Create menu exception") return False async def get(self) -> dict | None: token = self._gateway.access_token if self._gateway else None if not token: return None try: async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.get(f"{MENU_GET_URL}?access_token={token}") data = resp.json() if "menu" in data: return data logger.warning("Get menu failed: errcode=%s errmsg=%s", data.get("errcode"), data.get("errmsg")) except Exception: logger.exception("Get menu exception") return None async def delete(self) -> bool: token = self._gateway.access_token if self._gateway else None if not token: return False try: async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.get(f"{MENU_DELETE_URL}?access_token={token}") data = resp.json() return data.get("errcode") == 0 except Exception: logger.exception("Delete menu exception") return False async def add_conditional(self, buttons: list[dict], match_rule: dict) -> str | None: token = self._gateway.access_token if self._gateway else None if not token: return None payload = {"button": buttons, "matchrule": match_rule} try: async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.post(f"{MENU_ADD_CONDITIONAL_URL}?access_token={token}", json=payload) data = resp.json() if data.get("errcode") == 0: return data.get("menuid") logger.warning( "Add conditional menu failed: errcode=%s errmsg=%s", data.get("errcode"), data.get("errmsg"), ) except Exception: logger.exception("Add conditional menu exception") return None async def delete_conditional(self, menu_id: str) -> bool: token = self._gateway.access_token if self._gateway else None if not token: return False try: async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.post( f"{MENU_DEL_CONDITIONAL_URL}?access_token={token}", json={"menuid": menu_id} ) data = resp.json() return data.get("errcode") == 0 except Exception: logger.exception("Delete conditional menu exception") return False