test_admin_shortcuts.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. from __future__ import annotations
  2. from datetime import datetime
  3. from types import SimpleNamespace
  4. from unittest.mock import AsyncMock
  5. import pytest
  6. @pytest.mark.parametrize(
  7. ("text", "expected"),
  8. [
  9. ("封禁", ("/ban", ["ban"])),
  10. ("解封", ("/unban", ["unban"])),
  11. ("禁言", ("/mute", ["mute"])),
  12. ("解除禁言", ("/unmute", ["unmute"])),
  13. ("警告", ("/warn", ["warn"])),
  14. ("删除消息", ("/del", ["del"])),
  15. ("删除", ("/del", ["del"])),
  16. ("删", ("/del", ["del"])),
  17. ("禁言10分钟", ("/tmute 10m", ["tmute", "10m"])),
  18. (" 禁言1分钟 ", ("/tmute 1m", ["tmute", "1m"])),
  19. ("禁言1分钟", ("/tmute 1m", ["tmute", "1m"])),
  20. ("禁言\u200b1分钟", ("/tmute 1m", ["tmute", "1m"])),
  21. ("禁言 2 小时", ("/tmute 2h", ["tmute", "2h"])),
  22. ("禁言1天", ("/tmute 1d", ["tmute", "1d"])),
  23. ("踢出", ("/kick", ["kick"])),
  24. ("踢", ("/kick", ["kick"])),
  25. ("飞", ("/kick", ["kick"])),
  26. ],
  27. )
  28. def test_member_action_shortcut_parser(app_modules, text, expected):
  29. shortcuts = app_modules.load("wbb.services.member_shortcuts")
  30. assert shortcuts.member_action_shortcut_command(text) == expected
  31. @pytest.mark.parametrize("text", ["禁言0分钟", "禁言100分钟", "封禁 原因", "踢他"])
  32. def test_member_action_shortcut_rejects_ambiguous_text(app_modules, text):
  33. shortcuts = app_modules.load("wbb.services.member_shortcuts")
  34. assert shortcuts.member_action_shortcut_command(text) is None
  35. @pytest.mark.asyncio
  36. async def test_member_action_shortcut_executes_temporary_mute(
  37. app_modules, monkeypatch
  38. ):
  39. admin = app_modules.load("wbb.modules.admin")
  40. chat_id = -100123
  41. actor_id = 10
  42. target_id = 20
  43. privileges = SimpleNamespace(
  44. can_post_messages=False,
  45. can_edit_messages=False,
  46. can_delete_messages=True,
  47. can_restrict_members=True,
  48. can_promote_members=False,
  49. can_change_info=False,
  50. can_invite_users=False,
  51. can_pin_messages=False,
  52. can_manage_video_chats=False,
  53. )
  54. app_modules.app.members[(chat_id, actor_id)] = SimpleNamespace(
  55. privileges=privileges
  56. )
  57. app_modules.app.get_users = AsyncMock(
  58. return_value=SimpleNamespace(mention="@target")
  59. )
  60. monkeypatch.setattr(admin, "list_admins", AsyncMock(return_value=[]))
  61. restrict_member = AsyncMock()
  62. response = SimpleNamespace(chat=SimpleNamespace(id=chat_id), id=30)
  63. target_reply = AsyncMock(return_value=response)
  64. scheduled = []
  65. monkeypatch.setattr(
  66. admin,
  67. "schedule_group_cleanup",
  68. lambda *messages, **kwargs: scheduled.append((messages, kwargs)),
  69. )
  70. replied_message = SimpleNamespace(
  71. from_user=SimpleNamespace(id=target_id),
  72. sender_chat=None,
  73. reply_text=target_reply,
  74. )
  75. message = SimpleNamespace(
  76. text=" 禁言1分钟\u200b ",
  77. command=None,
  78. chat=SimpleNamespace(id=chat_id, restrict_member=restrict_member),
  79. from_user=SimpleNamespace(id=actor_id, mention="@admin"),
  80. sender_chat=None,
  81. reply_to_message=replied_message,
  82. reply_text=AsyncMock(),
  83. )
  84. assert await admin._member_action_shortcut_filter(None, None, message)
  85. await admin.member_action_shortcut(None, message)
  86. restrict_member.assert_awaited_once()
  87. args, kwargs = restrict_member.await_args
  88. assert args == (target_id,)
  89. assert kwargs["until_date"] > datetime.now()
  90. assert message.text == " 禁言1分钟\u200b "
  91. assert message.command is None
  92. assert "禁言时长:** 1m" in target_reply.await_args.args[0]
  93. assert "自动删除" not in target_reply.await_args.args[0]
  94. assert scheduled == [
  95. ((message, replied_message, response), {"delay_seconds": 10})
  96. ]
  97. @pytest.mark.asyncio
  98. async def test_delete_message_shortcut_waits_before_cleanup(
  99. app_modules, monkeypatch
  100. ):
  101. admin = app_modules.load("wbb.modules.admin")
  102. chat_id = -100123
  103. actor_id = 10
  104. privileges = SimpleNamespace(
  105. can_post_messages=False,
  106. can_edit_messages=False,
  107. can_delete_messages=True,
  108. can_restrict_members=True,
  109. can_promote_members=False,
  110. can_change_info=False,
  111. can_invite_users=False,
  112. can_pin_messages=False,
  113. can_manage_video_chats=False,
  114. )
  115. app_modules.app.members[(chat_id, actor_id)] = SimpleNamespace(
  116. privileges=privileges
  117. )
  118. response = SimpleNamespace(chat=SimpleNamespace(id=chat_id), id=31)
  119. target_reply = AsyncMock(return_value=response)
  120. replied_message = SimpleNamespace(
  121. from_user=SimpleNamespace(id=20),
  122. sender_chat=None,
  123. reply_text=target_reply,
  124. )
  125. message = SimpleNamespace(
  126. text="删除消息",
  127. command=None,
  128. chat=SimpleNamespace(id=chat_id),
  129. from_user=SimpleNamespace(id=actor_id, mention="@admin"),
  130. sender_chat=None,
  131. reply_to_message=replied_message,
  132. reply_text=AsyncMock(return_value=response),
  133. )
  134. scheduled = []
  135. monkeypatch.setattr(
  136. admin,
  137. "schedule_group_cleanup",
  138. lambda *messages, **kwargs: scheduled.append((messages, kwargs)),
  139. )
  140. await admin.member_action_shortcut(None, message)
  141. message.reply_text.assert_awaited_once()
  142. assert "自动删除" not in message.reply_text.await_args.args[0]
  143. target_reply.assert_not_awaited()
  144. assert scheduled == [
  145. ((message, replied_message, response), {"delay_seconds": 10})
  146. ]