feat: rebuild tg spam guard v2 architecture
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""群管理工具:权限校验、目标用户解析"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from telegram import Update
|
||||
from telegram.constants import ChatMemberStatus
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
import config
|
||||
from db.models import Action, Ban, Message
|
||||
from services.message_utils import schedule_delete
|
||||
|
||||
logger = logging.getLogger("spam_guard")
|
||||
|
||||
ADMIN_STATUSES = {ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.OWNER}
|
||||
|
||||
|
||||
async def is_admin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
|
||||
"""判断命令发送者是否为群管理员或配置中的超级管理员。"""
|
||||
user = update.effective_user
|
||||
chat = update.effective_chat
|
||||
if not user or not chat:
|
||||
return False
|
||||
if user.id in config.ADMIN_USER_IDS:
|
||||
return True
|
||||
try:
|
||||
member = await context.bot.get_chat_member(chat.id, user.id)
|
||||
return member.status in ADMIN_STATUSES
|
||||
except Exception as e:
|
||||
logger.warning(f"管理员校验失败: user={user.id}, chat={chat.id}, err={e}")
|
||||
return False
|
||||
|
||||
|
||||
async def require_admin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
|
||||
"""命令权限守卫。返回 True 表示允许继续。"""
|
||||
if await is_admin(update, context):
|
||||
return True
|
||||
reply = await update.message.reply_text("⛔ 只有群管理员可以使用这个命令")
|
||||
schedule_delete(update.message)
|
||||
schedule_delete(reply)
|
||||
return False
|
||||
|
||||
|
||||
async def resolve_target_user(update: Update, args: list[str]) -> tuple[int | None, str]:
|
||||
"""解析管理命令目标用户。
|
||||
|
||||
支持:
|
||||
1. 回复某条消息后执行命令
|
||||
2. /cmd 用户ID
|
||||
3. /cmd @username,从历史消息/操作/封禁记录中反查 user_id
|
||||
"""
|
||||
# 回复消息优先,最准确
|
||||
if update.message and update.message.reply_to_message and update.message.reply_to_message.from_user:
|
||||
u = update.message.reply_to_message.from_user
|
||||
username = u.username or u.first_name or str(u.id)
|
||||
return u.id, username
|
||||
|
||||
if not args:
|
||||
return None, ""
|
||||
|
||||
target = args[0].strip().lstrip("@")
|
||||
if target.isdigit():
|
||||
return int(target), target
|
||||
|
||||
# Telegram Bot API 不能直接用 username 查群成员,只能从历史记录里反查
|
||||
msg = await Message.filter(username=target).order_by("-created_at").first()
|
||||
if msg:
|
||||
return msg.user_id, target
|
||||
|
||||
action = await Action.filter(username=target, user_id__not_isnull=True).order_by("-created_at").first()
|
||||
if action:
|
||||
return action.user_id, target
|
||||
|
||||
ban = await Ban.filter(username=target).order_by("-created_at").first()
|
||||
if ban:
|
||||
return ban.user_id, target
|
||||
|
||||
return None, target
|
||||
Reference in New Issue
Block a user