乱点提示 @点击者:markdown 内联提及 <@openid>
This commit is contained in:
1 parent
755013b9db
commit
3fed0b0db1
3 files changed
+79
-9
No files matched your search
@@ -0,0 +1,47 @@
|
|||||||
|
# 密钥与本地配置(绝不提交)
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Python 运行产物
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# 虚拟环境
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# 运行时状态(禁言/验证进度,含成员 openid)
|
||||||
|
data/
|
||||||
|
|
||||||
|
# ZCode 工作目录
|
||||||
|
.zcode/
|
||||||
|
|
||||||
|
# ===== ↑ 以上同步自 .gitignore(「从 .gitignore 同步」只重写以上部分)=====
|
||||||
|
.git/
|
||||||
|
.hg/
|
||||||
|
.svn/
|
||||||
|
node_modules/
|
||||||
|
bower_components/
|
||||||
|
jspm_packages/
|
||||||
|
site-packages/
|
||||||
|
venv/
|
||||||
|
coverage/
|
||||||
|
htmlcov/
|
||||||
|
lcov-report/
|
||||||
|
cmakefiles/
|
||||||
|
cmake-build-*/
|
||||||
|
bazel-*/
|
||||||
|
pods/
|
||||||
|
deriveddata/
|
||||||
|
storybook-static/
|
||||||
|
playwright-report/
|
||||||
|
test-results/
|
||||||
|
allure-results/
|
||||||
|
allure-report/
|
||||||
|
cdk.out/
|
||||||
|
*.egg-info/
|
||||||
|
*.dist-info/
|
||||||
|
eggs/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
wheels/
|
||||||
|
# ----- ↑ 以上为 ZCode 默认排除规则(自定义规则请写在本行下方,不会被同步/恢复改动)-----
|
||||||
|
# 自定义规则写在下方(本行提示可删除)
|
||||||
+24
-4
@@ -96,10 +96,26 @@ async def set_member_mute(
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
async def _reply_text(api: BotApi, group_openid: str, text: str, *, event_id: str | None = None, msg_id: str | None = None) -> None:
|
async def _reply_text(
|
||||||
"""被动回复文本;窗口过期等失败降级为日志,不影响主流程。"""
|
api: BotApi, group_openid: str, text: str, *,
|
||||||
|
event_id: str | None = None, msg_id: str | None = None,
|
||||||
|
mention: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""被动回复文本;mention 传 openid 时改为 markdown 内联提及 @对方。
|
||||||
|
|
||||||
|
窗口过期等失败降级为日志,不影响主流程。提及必须走 markdown
|
||||||
|
(纯文本 content 不解析 <@> 语法)。
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
await api.post_group_message(group_openid, content=text, event_id=event_id, msg_id=msg_id)
|
if mention:
|
||||||
|
await api.post_group_message(
|
||||||
|
group_openid, markdown=f"<@{mention}> {text}",
|
||||||
|
event_id=event_id, msg_id=msg_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await api.post_group_message(
|
||||||
|
group_openid, content=text, event_id=event_id, msg_id=msg_id,
|
||||||
|
)
|
||||||
except ApiError as e:
|
except ApiError as e:
|
||||||
logger.warning(f"回复消息失败 (group={group_openid}): {e}")
|
logger.warning(f"回复消息失败 (group={group_openid}): {e}")
|
||||||
|
|
||||||
@@ -194,6 +210,7 @@ async def _handle_foreign_click(
|
|||||||
f"这道题不是给你的~(再乱点 {remaining} 次将被禁言 "
|
f"这道题不是给你的~(再乱点 {remaining} 次将被禁言 "
|
||||||
f"{cfg.foreign_click_mute_minutes} 分钟)",
|
f"{cfg.foreign_click_mute_minutes} 分钟)",
|
||||||
event_id=event_id,
|
event_id=event_id,
|
||||||
|
mention=member_openid,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -215,6 +232,7 @@ async def _handle_foreign_click(
|
|||||||
api, group_openid,
|
api, group_openid,
|
||||||
f"多次乱点他人的验证按钮,已禁言 {cfg.foreign_click_mute_minutes} 分钟。",
|
f"多次乱点他人的验证按钮,已禁言 {cfg.foreign_click_mute_minutes} 分钟。",
|
||||||
event_id=event_id,
|
event_id=event_id,
|
||||||
|
mention=member_openid,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await _reply_text(
|
await _reply_text(
|
||||||
@@ -222,6 +240,7 @@ async def _handle_foreign_click(
|
|||||||
"多次乱点他人的验证按钮!禁言未能生效(群主/管理员无法被禁言),"
|
"多次乱点他人的验证按钮!禁言未能生效(群主/管理员无法被禁言),"
|
||||||
"请管理员处理。",
|
"请管理员处理。",
|
||||||
event_id=event_id,
|
event_id=event_id,
|
||||||
|
mention=member_openid,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -350,7 +369,8 @@ def setup(bot: Bot, cfg: AuthConfig) -> VerifyState:
|
|||||||
else:
|
else:
|
||||||
# 旧题/已失效按钮,礼貌忽略不计处罚
|
# 旧题/已失效按钮,礼貌忽略不计处罚
|
||||||
await _reply_text(api, inter.group_openid, "这道题不是给你的~",
|
await _reply_text(api, inter.group_openid, "这道题不是给你的~",
|
||||||
event_id=event.event_id)
|
event_id=event.event_id,
|
||||||
|
mention=inter.group_member_openid)
|
||||||
return
|
return
|
||||||
if not is_subject:
|
if not is_subject:
|
||||||
await _reply_text(api, inter.group_openid, "这题已经被换掉啦,请回答最新一题",
|
await _reply_text(api, inter.group_openid, "这题已经被换掉啦,请回答最新一题",
|
||||||
|
|||||||
@@ -142,15 +142,17 @@ def test_foreign_clicker_muted_on_third_click(tmp_path, monkeypatch):
|
|||||||
|
|
||||||
# 每次点击都回应了互动
|
# 每次点击都回应了互动
|
||||||
assert len(fake.interactions_responded) == 3
|
assert len(fake.interactions_responded) == 3
|
||||||
# 前两次只有警告,第三次才禁言 5 分钟
|
# 前两次只有警告(markdown 内联提及点击者),第三次才禁言 5 分钟
|
||||||
warns = [m["content"] for m in fake.group_messages[:2]]
|
warns = [(m["markdown"] or "") for m in fake.group_messages[:2]]
|
||||||
assert all("不是给你的" in (c or "") for c in warns)
|
assert all("不是给你的" in md for md in warns)
|
||||||
|
assert all(f"<@MEMBER_B>" in md for md in warns)
|
||||||
mutes = [j for p, j in fake.raw_posts if p.endswith("/restrict_chat_setting")]
|
mutes = [j for p, j in fake.raw_posts if p.endswith("/restrict_chat_setting")]
|
||||||
assert len(mutes) == 1
|
assert len(mutes) == 1
|
||||||
entry = mutes[0]["members"][0]
|
entry = mutes[0]["members"][0]
|
||||||
assert entry["op"] == "add"
|
assert entry["op"] == "add"
|
||||||
assert entry["member_openid"] == "MEMBER_B"
|
assert entry["member_openid"] == "MEMBER_B"
|
||||||
assert "已禁言 5 分钟" in (fake.group_messages[-1]["content"] or "")
|
assert "已禁言 5 分钟" in (fake.group_messages[-1]["markdown"] or "")
|
||||||
|
assert "<@MEMBER_B>" in (fake.group_messages[-1]["markdown"] or "")
|
||||||
# 被试者的记录不受影响
|
# 被试者的记录不受影响
|
||||||
assert state.get(pending_key("GROUP1", "MEMBER_A")) is not None
|
assert state.get(pending_key("GROUP1", "MEMBER_A")) is not None
|
||||||
state.pop(pending_key("GROUP1", "MEMBER_A"))
|
state.pop(pending_key("GROUP1", "MEMBER_A"))
|
||||||
@@ -173,6 +175,7 @@ def test_stale_button_click_not_punished(tmp_path, monkeypatch):
|
|||||||
await asyncio.sleep(0.03)
|
await asyncio.sleep(0.03)
|
||||||
|
|
||||||
assert fake.raw_posts == [] # 三次都不触发禁言
|
assert fake.raw_posts == [] # 三次都不触发禁言
|
||||||
assert all("不是给你的" in (m["content"] or "") for m in fake.group_messages)
|
assert all("不是给你的" in (m["markdown"] or "") for m in fake.group_messages)
|
||||||
|
assert all("<@MEMBER_C>" in (m["markdown"] or "") for m in fake.group_messages)
|
||||||
|
|
||||||
asyncio.run(scenario())
|
asyncio.run(scenario())
|
||||||
Reference in new issue
Block a user