116 lines
4.5 KiB
Python
116 lines
4.5 KiB
Python
"""入群验证 handler"""
|
|
import asyncio
|
|
import logging
|
|
|
|
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
|
from telegram.ext import ContextTypes, CallbackQueryHandler, MessageHandler, filters
|
|
|
|
import config
|
|
from services.message_utils import record_bot_message
|
|
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("🎉 验证通过!欢迎加入群组!")
|
|
await record_bot_message(reply)
|
|
asyncio.create_task(auto_delete(reply))
|
|
await Action.create(action="VERIFY_PASS", chat_id=update.effective_chat.id, 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("❌ 验证失败次数过多,你将被移出群组")
|
|
await record_bot_message(reply)
|
|
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", chat_id=update.effective_chat.id, 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)} 次机会")
|
|
await record_bot_message(reply)
|
|
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)
|