fix: QQBot missing integration points, timestamp parsing, test fix

- Add Platform.QQBOT to _UPDATE_ALLOWED_PLATFORMS (enables /update command)
- Add 'qqbot' to webhook cross-platform delivery routing
- Add 'qqbot' to hermes dump platform detection
- Fix test_name_property casing: 'QQBot' not 'QQBOT'
- Add _parse_qq_timestamp() for ISO 8601 + integer ms compatibility
  (QQ API changed timestamp format — from PR #2411 finding)
- Wire timestamp parsing into all 4 message handlers
This commit is contained in:
Teknium
2026-04-13 22:46:50 -07:00
committed by Teknium
parent 884cd920d4
commit 4654f75627
5 changed files with 26 additions and 6 deletions

View File

@@ -756,7 +756,7 @@ class QQAdapter(BasePlatformAdapter):
message_id=msg_id,
media_urls=image_urls,
media_types=image_media_types,
timestamp=datetime.now(tz=timezone.utc),
timestamp=self._parse_qq_timestamp(timestamp),
)
await self.handle_message(event)
@@ -801,7 +801,7 @@ class QQAdapter(BasePlatformAdapter):
message_id=msg_id,
media_urls=image_urls,
media_types=image_media_types,
timestamp=datetime.now(tz=timezone.utc),
timestamp=self._parse_qq_timestamp(timestamp),
)
await self.handle_message(event)
@@ -846,7 +846,7 @@ class QQAdapter(BasePlatformAdapter):
message_id=msg_id,
media_urls=image_urls,
media_types=image_media_types,
timestamp=datetime.now(tz=timezone.utc),
timestamp=self._parse_qq_timestamp(timestamp),
)
await self.handle_message(event)
@@ -887,7 +887,7 @@ class QQAdapter(BasePlatformAdapter):
message_id=msg_id,
media_urls=image_urls,
media_types=image_media_types,
timestamp=datetime.now(tz=timezone.utc),
timestamp=self._parse_qq_timestamp(timestamp),
)
await self.handle_message(event)
@@ -1902,6 +1902,24 @@ class QQAdapter(BasePlatformAdapter):
return True
return False
def _parse_qq_timestamp(self, raw: str) -> datetime:
"""Parse QQ API timestamp (ISO 8601 string or integer ms).
The QQ API changed from integer milliseconds to ISO 8601 strings.
This handles both formats gracefully.
"""
if not raw:
return datetime.now(tz=timezone.utc)
try:
return datetime.fromisoformat(raw)
except (ValueError, TypeError):
pass
try:
return datetime.fromtimestamp(int(raw) / 1000, tz=timezone.utc)
except (ValueError, TypeError):
pass
return datetime.now(tz=timezone.utc)
def _is_duplicate(self, msg_id: str) -> bool:
now = time.time()
if len(self._seen_messages) > DEDUP_MAX_SIZE:

View File

@@ -203,6 +203,7 @@ class WebhookAdapter(BasePlatformAdapter):
"wecom_callback",
"weixin",
"bluebubbles",
"qqbot",
):
return await self._deliver_cross_platform(
deliver_type, content, delivery

View File

@@ -6480,7 +6480,7 @@ class GatewayRunner:
Platform.TELEGRAM, Platform.DISCORD, Platform.SLACK, Platform.WHATSAPP,
Platform.SIGNAL, Platform.MATTERMOST, Platform.MATRIX,
Platform.HOMEASSISTANT, Platform.EMAIL, Platform.SMS, Platform.DINGTALK,
Platform.FEISHU, Platform.WECOM, Platform.WECOM_CALLBACK, Platform.WEIXIN, Platform.BLUEBUBBLES, Platform.LOCAL,
Platform.FEISHU, Platform.WECOM, Platform.WECOM_CALLBACK, Platform.WEIXIN, Platform.BLUEBUBBLES, Platform.QQBOT, Platform.LOCAL,
})
async def _handle_debug_command(self, event: MessageEvent) -> str:

View File

@@ -131,6 +131,7 @@ def _configured_platforms() -> list[str]:
"wecom": "WECOM_BOT_ID",
"wecom_callback": "WECOM_CALLBACK_CORP_ID",
"weixin": "WEIXIN_ACCOUNT_ID",
"qqbot": "QQ_APP_ID",
}
return [name for name, env in checks.items() if os.getenv(env)]

View File

@@ -93,7 +93,7 @@ class TestQQAdapterInit:
def test_name_property(self):
adapter = self._make(app_id="a", client_secret="b")
assert adapter.name == "QQBOT"
assert adapter.name == "QQBot"
# ---------------------------------------------------------------------------