diff --git a/src/bot/handlers/basic.py b/src/bot/handlers/basic.py index cf49d6e7..7ddadb1c 100644 --- a/src/bot/handlers/basic.py +++ b/src/bot/handlers/basic.py @@ -247,6 +247,15 @@ class BasicCommandHandler: def handle_markets(self, message: Any) -> None: trace = CommandTrace("/markets", message) try: + chat_type = str(getattr(getattr(message, "chat", None), "type", "") or "").strip().lower() + if chat_type and chat_type != "private": + self.bot.reply_to( + message, + "ℹ️ `/markets` 仅支持私聊机器人查询。\n频道继续接收自动推送;如需手动查看当前市场概览,请私聊 bot 发送 `/markets`。", + parse_mode="Markdown", + ) + trace.set_status("blocked", f"unsupported_chat_type:{chat_type}") + return from src.utils.telegram_push import build_market_monitor_digest summary = build_market_monitor_digest( diff --git a/src/bot/io_layer.py b/src/bot/io_layer.py index 2cc9c106..42a1879c 100644 --- a/src/bot/io_layer.py +++ b/src/bot/io_layer.py @@ -178,7 +178,7 @@ class BotIOLayer: "可用指令:\n" f"/city [城市名] 或 /pwcity [城市名] - 查询城市天气预测与实测 (消耗 {CITY_QUERY_COST} 积分)\n" f"/deb [城市名] 或 /pwdeb [城市名] - 查看 DEB 融合预测准确率 (消耗 {DEB_QUERY_COST} 积分)\n" - "/markets - 查看当前市场监控摘要\n" + "/markets - 私聊机器人查看当前市场监控摘要\n" "/top - 查看积分排行榜\n" "/id - 获取当前聊天的 Chat ID\n\n" "/diag - 查看 Bot 启动诊断\n\n" @@ -186,6 +186,7 @@ class BotIOLayer: "/unbind - 解除当前 Telegram 与网页账号绑定\n\n" "🔗 机器人: @WeatherQuant_bot\n" "👥 社群: 加入 Telegram 群组\n\n" + "📌 私有频道用于接收自动推送;手动查看市场概览请私聊机器人发送 /markets\n\n" "🔐 /city 与 /deb 仅限官方群成员使用。\n\n" "示例: /city 伦敦/pwcity 伦敦\n" f"💡 提示: 每日签到(有效发言满 {MESSAGE_MIN_LENGTH} 字)获得 {MESSAGE_POINTS} 积分," diff --git a/tests/test_bot_basic_handler.py b/tests/test_bot_basic_handler.py index 10d88b2e..ffc42f26 100644 --- a/tests/test_bot_basic_handler.py +++ b/tests/test_bot_basic_handler.py @@ -25,7 +25,7 @@ def _message(text: str): return SimpleNamespace( text=text, from_user=SimpleNamespace(id=1, username="u", first_name="U"), - chat=SimpleNamespace(id=100), + chat=SimpleNamespace(id=100, type="private"), ) @@ -83,3 +83,30 @@ def test_basic_handler_markets_returns_summary(monkeypatch): assert len(bot.replies) == 1 assert bot.replies[0]["text"] == "MARKET DIGEST" + + +def test_basic_handler_markets_rejects_channel_chat(): + bot = DummyBot() + io_layer = SimpleNamespace( + build_welcome_text=lambda: "WELCOME", + build_points_rank_text=lambda _user: "TOP", + ) + handler = BasicCommandHandler( + bot=bot, + io_layer=io_layer, + runtime_status_provider=lambda: RuntimeStatus( + started_at="2026-03-12 00:00:00 UTC", + loops=[], + command_access_mode="group_member", + protected_commands=["/city", "/deb"], + required_group_chat_id="-1001234567890", + ), + config={}, + ) + + msg = _message("/markets") + msg.chat = SimpleNamespace(id=-1001, type="channel") + handler.handle_markets(msg) + + assert len(bot.replies) == 1 + assert "仅支持私聊机器人查询" in bot.replies[0]["text"]