fix: ban rule-based spam and add project icon
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<title>TG Spam Guard</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="TG Spam Guard">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="18" y1="12" x2="112" y2="116" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#4f46e5"/>
|
||||
<stop offset="0.52" stop-color="#0ea5e9"/>
|
||||
<stop offset="1" stop-color="#10b981"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="shield" x1="36" y1="24" x2="92" y2="104" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#ffffff"/>
|
||||
<stop offset="1" stop-color="#dbeafe"/>
|
||||
</linearGradient>
|
||||
<filter id="shadow" x="-30%" y="-30%" width="160%" height="160%">
|
||||
<feDropShadow dx="0" dy="8" stdDeviation="8" flood-color="#0f172a" flood-opacity="0.22"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<rect width="128" height="128" rx="30" fill="url(#bg)"/>
|
||||
<circle cx="100" cy="28" r="18" fill="#fff" opacity="0.16"/>
|
||||
<circle cx="24" cy="102" r="24" fill="#fff" opacity="0.12"/>
|
||||
<path filter="url(#shadow)" d="M64 18 98 31v28c0 24.8-13.9 43.8-34 52-20.1-8.2-34-27.2-34-52V31l34-13Z" fill="url(#shield)"/>
|
||||
<path d="M64 28 89 38v22c0 18.9-9.6 33.7-25 41-15.4-7.3-25-22.1-25-41V38l25-10Z" fill="#eef6ff" stroke="#bfdbfe" stroke-width="2"/>
|
||||
<path d="M37 59 86 39c3.1-1.3 5.9 2 4.2 4.9L76.7 68.2a7 7 0 0 1-4.2 3.3L60 75.2l-7.5 12.1c-1.6 2.6-5.6 1.5-5.6-1.6V78l-12.2-4.1c-3.4-1.1-3.7-5.9-.4-7.3L37 59Z" fill="#0ea5e9"/>
|
||||
<path d="M54.6 74.5 74.8 52.2 48.7 68.7l5.9 5.8Z" fill="#ffffff" opacity="0.92"/>
|
||||
<path d="M84 82.5 93.5 92m0-9.5L84 92" stroke="#ef4444" stroke-width="7" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
+6
-3
@@ -268,9 +268,12 @@ onBeforeUnmount(() => {
|
||||
<SConfigProvider :theme="{ theme: { primary: 'indigo' }, size: 'sm' }">
|
||||
<main class="page">
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<h1>🛡️ TG Spam Guard</h1>
|
||||
<p>Telegram 群组安全管理面板</p>
|
||||
<div class="brand">
|
||||
<img class="brand-icon" src="/icon.svg" alt="TG Spam Guard" />
|
||||
<div>
|
||||
<h1>TG Spam Guard</h1>
|
||||
<p>Telegram 群组安全管理面板</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-actions">
|
||||
<select v-model="selectedChatId" class="form-select" @change="reloadByGroup"><option :value="null">全部群组</option><option v-for="g in groups" :key="g.chat_id" :value="g.chat_id">{{ g.label || g.name }}</option></select>
|
||||
|
||||
@@ -8,6 +8,8 @@ body { margin: 0; min-height: 100vh; background: linear-gradient(135deg, #eef2ff
|
||||
button { font-family: inherit; }
|
||||
.page { min-height: 100vh; padding: 14px; padding-bottom: 82px; }
|
||||
.topbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; margin-bottom: 12px; border: 1px solid rgba(148,163,184,.28); border-radius: 18px; background: rgba(255,255,255,.86); box-shadow: 0 18px 40px rgba(15,23,42,.08); backdrop-filter: blur(12px); }
|
||||
.brand { display: flex; align-items: center; gap: 10px; }
|
||||
.brand-icon { width: 42px; height: 42px; border-radius: 12px; box-shadow: 0 10px 24px rgba(15,23,42,.16); }
|
||||
.topbar h1 { margin: 0; font-size: 22px; line-height: 1.1; }
|
||||
.topbar p { margin: 4px 0 0; color: #64748b; font-size: 12px; }
|
||||
.top-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
|
||||
|
||||
+20
-3
@@ -90,10 +90,20 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"reason": reason,
|
||||
}))
|
||||
|
||||
# 删消息
|
||||
# 删消息,并把记录标成已删除,避免前端继续显示“删除/删封”按钮
|
||||
try:
|
||||
await msg.delete()
|
||||
message_record.manually_deleted = True
|
||||
message_record.deleted_at = datetime.now()
|
||||
message_record.delete_reason = "auto_spam_delete"
|
||||
await message_record.save()
|
||||
await Action.create(action="DELETE", chat_id=update.effective_chat.id, user_id=user.id, username=username, details={"reason": reason, "text": text[:120]})
|
||||
await broadcast_sse("chat_delete", json_safe({
|
||||
"id": message_record.id,
|
||||
"msg_id": msg.message_id,
|
||||
"chat_id": update.effective_chat.id,
|
||||
"deleted_at": message_record.deleted_at,
|
||||
}))
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 删除消息失败: {e}")
|
||||
|
||||
@@ -135,10 +145,17 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
}))
|
||||
logger.info(f"🔨 已封禁 [{username}] {config.BAN_DURATION_MINUTES} 分钟")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 封禁失败: {e}")
|
||||
await Action.create(
|
||||
action="BAN_FAILED",
|
||||
chat_id=update.effective_chat.id,
|
||||
user_id=user.id,
|
||||
username=username,
|
||||
details={"reason": reason, "error": f"{type(e).__name__}: {e}"},
|
||||
)
|
||||
logger.error(f"❌ 封禁失败 [{username or user.id}]: {type(e).__name__}: {e}")
|
||||
|
||||
# 标记为垃圾
|
||||
await Message.filter(msg_id=msg.message_id).update(is_spam=True, spam_reason=reason)
|
||||
await Message.filter(chat_id=update.effective_chat.id, msg_id=msg.message_id).update(is_spam=True, spam_reason=reason)
|
||||
|
||||
|
||||
def register_spam(app):
|
||||
|
||||
@@ -118,7 +118,9 @@ SCORE_RULES = [
|
||||
# 营销常见词
|
||||
Rule("免费福利", r"(?:免费领|免费送|限时领|点击领取|扫码领取|福利|红包|返现|佣金|返佣)", 40),
|
||||
Rule("代理加盟", r"(?:代理|加盟|招商|推广返|分润|招募|招代理|合作共赢)", 45),
|
||||
Rule("豪车炫富", r"(?:换|开|提).{0,6}(?:迈巴赫|宝马|奔驰|保时捷|法拉利|兰博基尼)", 55),
|
||||
Rule("豪车炫富", r"(?:换|开|提).{0,8}(?:迈巴赫|宝马|奔驰|保时捷|法拉利|兰博基尼)", 65),
|
||||
Rule("月入收益承诺", r"(?:一个月|每月|月入|月赚|下个月).{0,12}(?:\d{1,4}|几万|几十万).{0,4}(?:w|W|万|个w|个W)", 75),
|
||||
Rule("安全收益承诺", r"(?:安全|稳赚|保本|不要本钱|不要本|零成本).{0,18}(?:赚|收益|月入|月赚|开奔驰|提车)", 70),
|
||||
]
|
||||
|
||||
# 组合加权:成熟广告识别关键在“组合意图”,不是单词命中
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="TG Spam Guard">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="18" y1="12" x2="112" y2="116" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#4f46e5"/>
|
||||
<stop offset="0.52" stop-color="#0ea5e9"/>
|
||||
<stop offset="1" stop-color="#10b981"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="shield" x1="36" y1="24" x2="92" y2="104" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#ffffff"/>
|
||||
<stop offset="1" stop-color="#dbeafe"/>
|
||||
</linearGradient>
|
||||
<filter id="shadow" x="-30%" y="-30%" width="160%" height="160%">
|
||||
<feDropShadow dx="0" dy="8" stdDeviation="8" flood-color="#0f172a" flood-opacity="0.22"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<rect width="128" height="128" rx="30" fill="url(#bg)"/>
|
||||
<circle cx="100" cy="28" r="18" fill="#fff" opacity="0.16"/>
|
||||
<circle cx="24" cy="102" r="24" fill="#fff" opacity="0.12"/>
|
||||
<path filter="url(#shadow)" d="M64 18 98 31v28c0 24.8-13.9 43.8-34 52-20.1-8.2-34-27.2-34-52V31l34-13Z" fill="url(#shield)"/>
|
||||
<path d="M64 28 89 38v22c0 18.9-9.6 33.7-25 41-15.4-7.3-25-22.1-25-41V38l25-10Z" fill="#eef6ff" stroke="#bfdbfe" stroke-width="2"/>
|
||||
<path d="M37 59 86 39c3.1-1.3 5.9 2 4.2 4.9L76.7 68.2a7 7 0 0 1-4.2 3.3L60 75.2l-7.5 12.1c-1.6 2.6-5.6 1.5-5.6-1.6V78l-12.2-4.1c-3.4-1.1-3.7-5.9-.4-7.3L37 59Z" fill="#0ea5e9"/>
|
||||
<path d="M54.6 74.5 74.8 52.2 48.7 68.7l5.9 5.8Z" fill="#ffffff" opacity="0.92"/>
|
||||
<path d="M84 82.5 93.5 92m0-9.5L84 92" stroke="#ef4444" stroke-width="7" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -3,9 +3,10 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/static/icon.svg" />
|
||||
<title>TG Spam Guard</title>
|
||||
<script type="module" crossorigin src="/static/assets/index-Cwa1Xd8Y.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-CVeOFNWl.css">
|
||||
<script type="module" crossorigin src="/static/assets/index-B7wPhEjS.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/assets/index-zEILxixw.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
Reference in New Issue
Block a user