Files
tg-spam-guard/handlers/verify.py
T

112 lines
4.2 KiB
Python

"""入群验证 handler"""
import asyncio
import logging
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import ContextTypes, CallbackQueryHandler, MessageHandler, filters
import config
from db.models import Action
from services.verify_service import create_verify, check_answer, get_pending_verify
logger = logging.getLogger("spam_guard")
async def handle_verify_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理验证按钮回调"""
query = update.callback_query
await query.answer()
user = query.from_user
data = query.data
if data == "start_verify":
result = await get_pending_verify(user.id)
if not result:
result = await create_verify(user.id, user.username)
await query.edit_message_text(
f"✅ 验证问题:\n\n{result['question']}\n\n"
f"请直接回复你的答案(文字消息)"
)
context.user_data["verifying"] = True
context.user_data["verify_user_id"] = user.id
if query.message:
asyncio.create_task(auto_delete(query.message))
elif data == "verify_help":
await query.edit_message_text(
"💡 验证帮助\n\n"
"请直接在群内发送你的答案文字消息。\n"
f"你有 {config.VERIFY_MAX_ATTEMPTS} 次机会"
)
if query.message:
asyncio.create_task(auto_delete(query.message))
async def handle_verify_answer(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理验证回答。用户答案不删,只焚毁 Bot 回复。"""
if not context.user_data.get("verifying"):
return
user_id = context.user_data.get("verify_user_id", update.effective_user.id)
answer = update.message.text.strip()
result = await check_answer(user_id, answer)
asyncio.create_task(auto_delete(update.message, seconds=60))
if result["ok"]:
context.user_data["verifying"] = False
try:
from telegram import ChatPermissions
await update.effective_chat.restrict_member(
user_id=user_id,
permissions=ChatPermissions(
can_send_messages=True,
can_send_audios=True,
can_send_documents=True,
can_send_photos=True,
can_send_videos=True,
can_send_video_notes=True,
can_send_voice_notes=True,
can_send_polls=True,
can_send_other_messages=True,
can_add_web_page_previews=True,
can_invite_users=True,
),
)
except Exception as e:
logger.error(f"⚠️ 恢复权限失败: {e}")
reply = await update.message.reply_text("🎉 验证通过!欢迎加入群组!")
asyncio.create_task(auto_delete(reply))
await Action.create(action="VERIFY_PASS", user_id=user_id, username=update.effective_user.username)
logger.info(f"✅ 验证通过: {user_id}")
return
if result["reason"] == "max_attempts":
context.user_data["verifying"] = False
reply = await update.message.reply_text("❌ 验证失败次数过多,你将被移出群组")
asyncio.create_task(auto_delete(reply))
try:
await update.effective_chat.ban_member(user_id=user_id)
await asyncio.sleep(5)
await update.effective_chat.unban_member(user_id=user_id)
except Exception:
pass
await Action.create(action="VERIFY_FAIL", user_id=user_id, username=update.effective_user.username)
else:
reply = await update.message.reply_text(f"❌ 答案错误,剩余 {config.VERIFY_MAX_ATTEMPTS - result.get('attempts', 0)} 次机会")
asyncio.create_task(auto_delete(reply))
async def auto_delete(message, seconds=60):
try:
await asyncio.sleep(seconds)
await message.delete()
except Exception:
pass
def register_verify(app):
app.add_handler(CallbackQueryHandler(handle_verify_callback, pattern=r"^(start_verify|verify_help)$"))
app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.GROUPS & ~filters.COMMAND, handle_verify_answer), group=1)