Jelajahi Sumber

feat: auto-clean member shortcut messages

AI-Co-Authored-By: Codex
chendeben 1 Minggu lalu
induk
melakukan
b4e2f47fe0
3 mengubah file dengan 111 tambahan dan 2 penghapusan
  1. 69 1
      tests/test_admin_shortcuts.py
  2. 40 1
      wbb/modules/admin.py
  3. 2 0
      wbb/services/member_shortcuts.py

+ 69 - 1
tests/test_admin_shortcuts.py

@@ -15,6 +15,9 @@ import pytest
         ("禁言", ("/mute", ["mute"])),
         ("解除禁言", ("/unmute", ["unmute"])),
         ("警告", ("/warn", ["warn"])),
+        ("删除消息", ("/del", ["del"])),
+        ("删除", ("/del", ["del"])),
+        ("删", ("/del", ["del"])),
         ("禁言10分钟", ("/tmute 10m", ["tmute", "10m"])),
         ("  禁言1分钟  ", ("/tmute 1m", ["tmute", "1m"])),
         ("禁言1分钟", ("/tmute 1m", ["tmute", "1m"])),
@@ -65,7 +68,14 @@ async def test_member_action_shortcut_executes_temporary_mute(
     monkeypatch.setattr(admin, "list_admins", AsyncMock(return_value=[]))
 
     restrict_member = AsyncMock()
-    target_reply = AsyncMock()
+    response = SimpleNamespace(chat=SimpleNamespace(id=chat_id), id=30)
+    target_reply = AsyncMock(return_value=response)
+    scheduled = []
+    monkeypatch.setattr(
+        admin,
+        "schedule_group_cleanup",
+        lambda *messages, **kwargs: scheduled.append((messages, kwargs)),
+    )
     replied_message = SimpleNamespace(
         from_user=SimpleNamespace(id=target_id),
         sender_chat=None,
@@ -91,3 +101,61 @@ async def test_member_action_shortcut_executes_temporary_mute(
     assert message.text == "  禁言1分钟\u200b  "
     assert message.command is None
     assert "禁言时长:** 1m" in target_reply.await_args.args[0]
+    assert "10 秒后自动删除" in target_reply.await_args.args[0]
+    assert scheduled == [
+        ((message, replied_message, response), {"delay_seconds": 10})
+    ]
+
+
+@pytest.mark.asyncio
+async def test_delete_message_shortcut_waits_before_cleanup(
+    app_modules, monkeypatch
+):
+    admin = app_modules.load("wbb.modules.admin")
+    chat_id = -100123
+    actor_id = 10
+    privileges = SimpleNamespace(
+        can_post_messages=False,
+        can_edit_messages=False,
+        can_delete_messages=True,
+        can_restrict_members=True,
+        can_promote_members=False,
+        can_change_info=False,
+        can_invite_users=False,
+        can_pin_messages=False,
+        can_manage_video_chats=False,
+    )
+    app_modules.app.members[(chat_id, actor_id)] = SimpleNamespace(
+        privileges=privileges
+    )
+    response = SimpleNamespace(chat=SimpleNamespace(id=chat_id), id=31)
+    target_reply = AsyncMock(return_value=response)
+    replied_message = SimpleNamespace(
+        from_user=SimpleNamespace(id=20),
+        sender_chat=None,
+        reply_text=target_reply,
+    )
+    message = SimpleNamespace(
+        text="删除消息",
+        command=None,
+        chat=SimpleNamespace(id=chat_id),
+        from_user=SimpleNamespace(id=actor_id, mention="@admin"),
+        sender_chat=None,
+        reply_to_message=replied_message,
+        reply_text=AsyncMock(return_value=response),
+    )
+    scheduled = []
+    monkeypatch.setattr(
+        admin,
+        "schedule_group_cleanup",
+        lambda *messages, **kwargs: scheduled.append((messages, kwargs)),
+    )
+
+    await admin.member_action_shortcut(None, message)
+
+    message.reply_text.assert_awaited_once()
+    assert "10 秒后自动删除" in message.reply_text.await_args.args[0]
+    target_reply.assert_not_awaited()
+    assert scheduled == [
+        ((message, replied_message, response), {"delay_seconds": 10})
+    ]

+ 40 - 1
wbb/modules/admin.py

@@ -44,6 +44,7 @@ from wbb.services.bot_permissions import has_permission
 from wbb.services.member_shortcuts import (
     member_action_shortcut_command,
 )
+from wbb.services.message_cleanup import schedule_group_cleanup
 from wbb.utils.dbfunctions import (
     add_warn,
     get_warn,
@@ -81,9 +82,15 @@ __HELP__ = """/ban - 封禁成员。
 /report、@admins 或 @admin - 向管理员举报消息。
 /invite - 获取群邀请链接。
 回复成员消息发送“封禁”“解封”“禁言”“禁言10分钟”“解除禁言”、
-“警告”“踢出”“踢”或“飞”,
+“警告”“删除消息”“删除”“删”“踢出”“踢”或“飞”,
 可快捷执行对应管理操作。"""
 
+MEMBER_ACTION_CLEANUP_SECONDS = 10
+MEMBER_ACTION_CLEANUP_NOTICE = (
+    "\n\n⏳ 本提示、快捷指令及被回复消息将在 10 秒后自动删除。"
+)
+
+
 async def member_permissions(chat_id: int, user_id: int):
     perms = []
     member = (await app.get_chat_member(chat_id, user_id)).privileges
@@ -641,6 +648,11 @@ member_action_shortcut_filter = filters.create(
 )
 
 
+@adminsOnly("can_delete_messages")
+async def delete_shortcut(_, message: Message):
+    await message.reply_text("已接收删除请求。")
+
+
 @app.on_message(
     filters.group & filters.reply & member_action_shortcut_filter,
     group=-999,
@@ -655,6 +667,29 @@ async def member_action_shortcut(client, message: Message):
         return None
     original_text = message.text
     original_command = message.command
+    replied_message = message.reply_to_message
+    original_message_reply = message.reply_text
+    original_target_reply = replied_message.reply_text
+
+    def cleanup_reply(original_reply):
+        async def wrapped_reply(text, *args, **kwargs):
+            response = await original_reply(
+                f"{text}{MEMBER_ACTION_CLEANUP_NOTICE}",
+                *args,
+                **kwargs,
+            )
+            schedule_group_cleanup(
+                message,
+                replied_message,
+                response,
+                delay_seconds=MEMBER_ACTION_CLEANUP_SECONDS,
+            )
+            return response
+
+        return wrapped_reply
+
+    message.reply_text = cleanup_reply(original_message_reply)
+    replied_message.reply_text = cleanup_reply(original_target_reply)
     message.text, message.command = command
     log.info(
         f"成员快捷操作:chat={message.chat.id} "
@@ -672,10 +707,14 @@ async def member_action_shortcut(client, message: Message):
             return await unban_func(client, message)
         if message.command[0] == "unmute":
             return await unmute(client, message)
+        if message.command[0] == "del":
+            return await delete_shortcut(client, message)
         return await kickFunc(client, message)
     finally:
         message.text = original_text
         message.command = original_command
+        message.reply_text = original_message_reply
+        replied_message.reply_text = original_target_reply
 
 
 # Unmute members

+ 2 - 0
wbb/services/member_shortcuts.py

@@ -21,6 +21,8 @@ def member_action_shortcut_command(text: str) -> tuple[str, list[str]] | None:
         return "/unban", ["unban"]
     if normalized == "解除禁言":
         return "/unmute", ["unmute"]
+    if normalized in {"删除消息", "删除", "删"}:
+        return "/del", ["del"]
     duration = re.fullmatch(
         r"禁言\s*([1-9]\d?)\s*(分钟|分|小时|时|天)", normalized
     )