fix: WeCom sender_name shows user ID instead of actual username

- Add get_user_info() to WecomClient to fetch user name via /user/get API
- Update WecomEventConverter.target2yiri to accept bot param and fetch real user name
- Update register_listener call to pass self.bot for user name lookup
- URL-encode userid parameter for safety

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-11 17:52:43 +00:00
parent 5290834b8b
commit def798bf1f
2 changed files with 41 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ import base64
import binascii import binascii
import httpx import httpx
import traceback import traceback
from urllib.parse import quote
from quart import Quart from quart import Quart
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from typing import Callable, Dict, Any from typing import Callable, Dict, Any
@@ -67,6 +68,31 @@ class WecomClient:
await self.logger.error(f'获取accesstoken失败:{response.json()}') await self.logger.error(f'获取accesstoken失败:{response.json()}')
raise Exception(f'未获取access token: {data}') raise Exception(f'未获取access token: {data}')
async def get_user_info(self, userid: str) -> dict:
"""
Get user information by user ID using the contacts secret.
Args:
userid: The user ID to look up.
Returns:
dict: User information including 'name' field.
"""
if not await self.check_access_token_for_contacts():
self.access_token_for_contacts = await self.get_access_token(self.secret_for_contacts)
url = self.base_url + '/user/get?access_token=' + self.access_token_for_contacts + '&userid=' + quote(userid)
async with httpx.AsyncClient() as client:
response = await client.get(url)
data = response.json()
if data.get('errcode') == 40014 or data.get('errcode') == 42001:
self.access_token_for_contacts = await self.get_access_token(self.secret_for_contacts)
return await self.get_user_info(userid)
if data.get('errcode', 0) != 0:
await self.logger.error(f'获取用户信息失败:{data}')
return {}
return data
async def get_users(self): async def get_users(self):
if not self.check_access_token_for_contacts(): if not self.check_access_token_for_contacts():
self.access_token_for_contacts = await self.get_access_token(self.secret_for_contacts) self.access_token_for_contacts = await self.get_access_token(self.secret_for_contacts)

View File

@@ -163,22 +163,33 @@ class WecomEventConverter(abstract_platform_adapter.AbstractEventConverter):
return wecom_event return wecom_event
@staticmethod @staticmethod
async def target2yiri(event: WecomEvent): async def target2yiri(event: WecomEvent, bot: WecomClient = None):
""" """
将 WecomEvent 转换为平台的 FriendMessage 对象。 将 WecomEvent 转换为平台的 FriendMessage 对象。
Args: Args:
event (WecomEvent): 企业微信事件。 event (WecomEvent): 企业微信事件。
bot (WecomClient): 企业微信客户端,用于获取用户信息。
Returns: Returns:
platform_events.FriendMessage: 转换后的 FriendMessage 对象。 platform_events.FriendMessage: 转换后的 FriendMessage 对象。
""" """
# Try to get the user's real name from the WeCom API
nickname = str(event.user_id)
if bot and event.user_id:
try:
user_info = await bot.get_user_info(event.user_id)
if user_info and user_info.get('name'):
nickname = user_info.get('name')
except Exception:
pass # Fall back to user_id as nickname
# 转换消息链 # 转换消息链
if event.type == 'text': if event.type == 'text':
yiri_chain = await WecomMessageConverter.target2yiri(event.message, event.message_id) yiri_chain = await WecomMessageConverter.target2yiri(event.message, event.message_id)
friend = platform_entities.Friend( friend = platform_entities.Friend(
id=f'u{event.user_id}', id=f'u{event.user_id}',
nickname=str(event.agent_id), nickname=nickname,
remark='', remark='',
) )
@@ -186,7 +197,7 @@ class WecomEventConverter(abstract_platform_adapter.AbstractEventConverter):
elif event.type == 'image': elif event.type == 'image':
friend = platform_entities.Friend( friend = platform_entities.Friend(
id=f'u{event.user_id}', id=f'u{event.user_id}',
nickname=str(event.agent_id), nickname=nickname,
remark='', remark='',
) )
@@ -287,7 +298,7 @@ class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
async def on_message(event: WecomEvent): async def on_message(event: WecomEvent):
self.bot_account_id = event.receiver_id self.bot_account_id = event.receiver_id
try: try:
return await callback(await self.event_converter.target2yiri(event), self) return await callback(await self.event_converter.target2yiri(event, self.bot), self)
except Exception: except Exception:
await self.logger.error(f'Error in wecom callback: {traceback.format_exc()}') await self.logger.error(f'Error in wecom callback: {traceback.format_exc()}')